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 element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229
  230pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  231pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  232pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  233
  234pub type RenderDiffHunkControlsFn = Arc<
  235    dyn Fn(
  236        u32,
  237        &DiffHunkStatus,
  238        Range<Anchor>,
  239        bool,
  240        Pixels,
  241        &Entity<Editor>,
  242        &mut Window,
  243        &mut App,
  244    ) -> AnyElement,
  245>;
  246
  247enum ReportEditorEvent {
  248    Saved { auto_saved: bool },
  249    EditorOpened,
  250    Closed,
  251}
  252
  253impl ReportEditorEvent {
  254    pub fn event_type(&self) -> &'static str {
  255        match self {
  256            Self::Saved { .. } => "Editor Saved",
  257            Self::EditorOpened => "Editor Opened",
  258            Self::Closed => "Editor Closed",
  259        }
  260    }
  261}
  262
  263struct InlineValueCache {
  264    enabled: bool,
  265    inlays: Vec<InlayId>,
  266    refresh_task: Task<Option<()>>,
  267}
  268
  269impl InlineValueCache {
  270    fn new(enabled: bool) -> Self {
  271        Self {
  272            enabled,
  273            inlays: Vec::new(),
  274            refresh_task: Task::ready(None),
  275        }
  276    }
  277}
  278
  279#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  280pub enum InlayId {
  281    EditPrediction(u32),
  282    DebuggerValue(u32),
  283    // LSP
  284    Hint(u32),
  285    Color(u32),
  286}
  287
  288impl InlayId {
  289    fn id(&self) -> u32 {
  290        match self {
  291            Self::EditPrediction(id) => *id,
  292            Self::DebuggerValue(id) => *id,
  293            Self::Hint(id) => *id,
  294            Self::Color(id) => *id,
  295        }
  296    }
  297}
  298
  299pub enum ActiveDebugLine {}
  300pub enum DebugStackFrameLine {}
  301enum DocumentHighlightRead {}
  302enum DocumentHighlightWrite {}
  303enum InputComposition {}
  304pub enum PendingInput {}
  305enum SelectedTextHighlight {}
  306
  307pub enum ConflictsOuter {}
  308pub enum ConflictsOurs {}
  309pub enum ConflictsTheirs {}
  310pub enum ConflictsOursMarker {}
  311pub enum ConflictsTheirsMarker {}
  312
  313#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  314pub enum Navigated {
  315    Yes,
  316    No,
  317}
  318
  319impl Navigated {
  320    pub fn from_bool(yes: bool) -> Navigated {
  321        if yes { Navigated::Yes } else { Navigated::No }
  322    }
  323}
  324
  325#[derive(Debug, Clone, PartialEq, Eq)]
  326enum DisplayDiffHunk {
  327    Folded {
  328        display_row: DisplayRow,
  329    },
  330    Unfolded {
  331        is_created_file: bool,
  332        diff_base_byte_range: Range<usize>,
  333        display_row_range: Range<DisplayRow>,
  334        multi_buffer_range: Range<Anchor>,
  335        status: DiffHunkStatus,
  336    },
  337}
  338
  339pub enum HideMouseCursorOrigin {
  340    TypingAction,
  341    MovementAction,
  342}
  343
  344pub fn init_settings(cx: &mut App) {
  345    EditorSettings::register(cx);
  346}
  347
  348pub fn init(cx: &mut App) {
  349    init_settings(cx);
  350
  351    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  352
  353    workspace::register_project_item::<Editor>(cx);
  354    workspace::FollowableViewRegistry::register::<Editor>(cx);
  355    workspace::register_serializable_item::<Editor>(cx);
  356
  357    cx.observe_new(
  358        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  359            workspace.register_action(Editor::new_file);
  360            workspace.register_action(Editor::new_file_vertical);
  361            workspace.register_action(Editor::new_file_horizontal);
  362            workspace.register_action(Editor::cancel_language_server_work);
  363            workspace.register_action(Editor::toggle_focus);
  364        },
  365    )
  366    .detach();
  367
  368    cx.on_action(move |_: &workspace::NewFile, cx| {
  369        let app_state = workspace::AppState::global(cx);
  370        if let Some(app_state) = app_state.upgrade() {
  371            workspace::open_new(
  372                Default::default(),
  373                app_state,
  374                cx,
  375                |workspace, window, cx| {
  376                    Editor::new_file(workspace, &Default::default(), window, cx)
  377                },
  378            )
  379            .detach();
  380        }
  381    });
  382    cx.on_action(move |_: &workspace::NewWindow, cx| {
  383        let app_state = workspace::AppState::global(cx);
  384        if let Some(app_state) = app_state.upgrade() {
  385            workspace::open_new(
  386                Default::default(),
  387                app_state,
  388                cx,
  389                |workspace, window, cx| {
  390                    cx.activate(true);
  391                    Editor::new_file(workspace, &Default::default(), window, cx)
  392                },
  393            )
  394            .detach();
  395        }
  396    });
  397}
  398
  399pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  400    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  401}
  402
  403pub trait DiagnosticRenderer {
  404    fn render_group(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  407        buffer_id: BufferId,
  408        snapshot: EditorSnapshot,
  409        editor: WeakEntity<Editor>,
  410        cx: &mut App,
  411    ) -> Vec<BlockProperties<Anchor>>;
  412
  413    fn render_hover(
  414        &self,
  415        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  416        range: Range<Point>,
  417        buffer_id: BufferId,
  418        cx: &mut App,
  419    ) -> Option<Entity<markdown::Markdown>>;
  420
  421    fn open_link(
  422        &self,
  423        editor: &mut Editor,
  424        link: SharedString,
  425        window: &mut Window,
  426        cx: &mut Context<Editor>,
  427    );
  428}
  429
  430pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  431
  432impl GlobalDiagnosticRenderer {
  433    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  434        cx.try_global::<Self>().map(|g| g.0.clone())
  435    }
  436}
  437
  438impl gpui::Global for GlobalDiagnosticRenderer {}
  439pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  440    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  441}
  442
  443pub struct SearchWithinRange;
  444
  445trait InvalidationRegion {
  446    fn ranges(&self) -> &[Range<Anchor>];
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum SelectPhase {
  451    Begin {
  452        position: DisplayPoint,
  453        add: bool,
  454        click_count: usize,
  455    },
  456    BeginColumnar {
  457        position: DisplayPoint,
  458        reset: bool,
  459        mode: ColumnarMode,
  460        goal_column: u32,
  461    },
  462    Extend {
  463        position: DisplayPoint,
  464        click_count: usize,
  465    },
  466    Update {
  467        position: DisplayPoint,
  468        goal_column: u32,
  469        scroll_delta: gpui::Point<f32>,
  470    },
  471    End,
  472}
  473
  474#[derive(Clone, Debug, PartialEq)]
  475pub enum ColumnarMode {
  476    FromMouse,
  477    FromSelection,
  478}
  479
  480#[derive(Clone, Debug)]
  481pub enum SelectMode {
  482    Character,
  483    Word(Range<Anchor>),
  484    Line(Range<Anchor>),
  485    All,
  486}
  487
  488#[derive(Clone, PartialEq, Eq, Debug)]
  489pub enum EditorMode {
  490    SingleLine,
  491    AutoHeight {
  492        min_lines: usize,
  493        max_lines: Option<usize>,
  494    },
  495    Full {
  496        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  497        scale_ui_elements_with_buffer_font_size: bool,
  498        /// When set to `true`, the editor will render a background for the active line.
  499        show_active_line_background: bool,
  500        /// When set to `true`, the editor's height will be determined by its content.
  501        sized_by_content: bool,
  502    },
  503    Minimap {
  504        parent: WeakEntity<Editor>,
  505    },
  506}
  507
  508impl EditorMode {
  509    pub fn full() -> Self {
  510        Self::Full {
  511            scale_ui_elements_with_buffer_font_size: true,
  512            show_active_line_background: true,
  513            sized_by_content: false,
  514        }
  515    }
  516
  517    #[inline]
  518    pub fn is_full(&self) -> bool {
  519        matches!(self, Self::Full { .. })
  520    }
  521
  522    #[inline]
  523    pub fn is_single_line(&self) -> bool {
  524        matches!(self, Self::SingleLine { .. })
  525    }
  526
  527    #[inline]
  528    fn is_minimap(&self) -> bool {
  529        matches!(self, Self::Minimap { .. })
  530    }
  531}
  532
  533#[derive(Copy, Clone, Debug)]
  534pub enum SoftWrap {
  535    /// Prefer not to wrap at all.
  536    ///
  537    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  538    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  539    GitDiff,
  540    /// Prefer a single line generally, unless an overly long line is encountered.
  541    None,
  542    /// Soft wrap lines that exceed the editor width.
  543    EditorWidth,
  544    /// Soft wrap lines at the preferred line length.
  545    Column(u32),
  546    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  547    Bounded(u32),
  548}
  549
  550#[derive(Clone)]
  551pub struct EditorStyle {
  552    pub background: Hsla,
  553    pub border: Hsla,
  554    pub local_player: PlayerColor,
  555    pub text: TextStyle,
  556    pub scrollbar_width: Pixels,
  557    pub syntax: Arc<SyntaxTheme>,
  558    pub status: StatusColors,
  559    pub inlay_hints_style: HighlightStyle,
  560    pub edit_prediction_styles: EditPredictionStyles,
  561    pub unnecessary_code_fade: f32,
  562    pub show_underlines: bool,
  563}
  564
  565impl Default for EditorStyle {
  566    fn default() -> Self {
  567        Self {
  568            background: Hsla::default(),
  569            border: Hsla::default(),
  570            local_player: PlayerColor::default(),
  571            text: TextStyle::default(),
  572            scrollbar_width: Pixels::default(),
  573            syntax: Default::default(),
  574            // HACK: Status colors don't have a real default.
  575            // We should look into removing the status colors from the editor
  576            // style and retrieve them directly from the theme.
  577            status: StatusColors::dark(),
  578            inlay_hints_style: HighlightStyle::default(),
  579            edit_prediction_styles: EditPredictionStyles {
  580                insertion: HighlightStyle::default(),
  581                whitespace: HighlightStyle::default(),
  582            },
  583            unnecessary_code_fade: Default::default(),
  584            show_underlines: true,
  585        }
  586    }
  587}
  588
  589pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  590    let show_background = language_settings::language_settings(None, None, cx)
  591        .inlay_hints
  592        .show_background;
  593
  594    let mut style = cx.theme().syntax().get("hint");
  595
  596    if style.color.is_none() {
  597        style.color = Some(cx.theme().status().hint);
  598    }
  599
  600    if !show_background {
  601        style.background_color = None;
  602        return style;
  603    }
  604
  605    if style.background_color.is_none() {
  606        style.background_color = Some(cx.theme().status().hint_background);
  607    }
  608
  609    style
  610}
  611
  612pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  613    EditPredictionStyles {
  614        insertion: HighlightStyle {
  615            color: Some(cx.theme().status().predictive),
  616            ..HighlightStyle::default()
  617        },
  618        whitespace: HighlightStyle {
  619            background_color: Some(cx.theme().status().created_background),
  620            ..HighlightStyle::default()
  621        },
  622    }
  623}
  624
  625type CompletionId = usize;
  626
  627pub(crate) enum EditDisplayMode {
  628    TabAccept,
  629    DiffPopover,
  630    Inline,
  631}
  632
  633enum EditPrediction {
  634    Edit {
  635        edits: Vec<(Range<Anchor>, String)>,
  636        edit_preview: Option<EditPreview>,
  637        display_mode: EditDisplayMode,
  638        snapshot: BufferSnapshot,
  639    },
  640    /// Move to a specific location in the active editor
  641    MoveWithin {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645    /// Move to a specific location in a different editor (not the active one)
  646    MoveOutside {
  647        target: language::Anchor,
  648        snapshot: BufferSnapshot,
  649    },
  650}
  651
  652struct EditPredictionState {
  653    inlay_ids: Vec<InlayId>,
  654    completion: EditPrediction,
  655    completion_id: Option<SharedString>,
  656    invalidation_range: Option<Range<Anchor>>,
  657}
  658
  659enum EditPredictionSettings {
  660    Disabled,
  661    Enabled {
  662        show_in_menu: bool,
  663        preview_requires_modifier: bool,
  664    },
  665}
  666
  667enum EditPredictionHighlight {}
  668
  669#[derive(Debug, Clone)]
  670struct InlineDiagnostic {
  671    message: SharedString,
  672    group_id: usize,
  673    is_primary: bool,
  674    start: Point,
  675    severity: lsp::DiagnosticSeverity,
  676}
  677
  678pub enum MenuEditPredictionsPolicy {
  679    Never,
  680    ByProvider,
  681}
  682
  683pub enum EditPredictionPreview {
  684    /// Modifier is not pressed
  685    Inactive { released_too_fast: bool },
  686    /// Modifier pressed
  687    Active {
  688        since: Instant,
  689        previous_scroll_position: Option<ScrollAnchor>,
  690    },
  691}
  692
  693impl EditPredictionPreview {
  694    pub fn released_too_fast(&self) -> bool {
  695        match self {
  696            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  697            EditPredictionPreview::Active { .. } => false,
  698        }
  699    }
  700
  701    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  702        if let EditPredictionPreview::Active {
  703            previous_scroll_position,
  704            ..
  705        } = self
  706        {
  707            *previous_scroll_position = scroll_position;
  708        }
  709    }
  710}
  711
  712pub struct ContextMenuOptions {
  713    pub min_entries_visible: usize,
  714    pub max_entries_visible: usize,
  715    pub placement: Option<ContextMenuPlacement>,
  716}
  717
  718#[derive(Debug, Clone, PartialEq, Eq)]
  719pub enum ContextMenuPlacement {
  720    Above,
  721    Below,
  722}
  723
  724#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  725struct EditorActionId(usize);
  726
  727impl EditorActionId {
  728    pub fn post_inc(&mut self) -> Self {
  729        let answer = self.0;
  730
  731        *self = Self(answer + 1);
  732
  733        Self(answer)
  734    }
  735}
  736
  737// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  738// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  739
  740type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  741type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  742
  743#[derive(Default)]
  744struct ScrollbarMarkerState {
  745    scrollbar_size: Size<Pixels>,
  746    dirty: bool,
  747    markers: Arc<[PaintQuad]>,
  748    pending_refresh: Option<Task<Result<()>>>,
  749}
  750
  751impl ScrollbarMarkerState {
  752    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  753        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  754    }
  755}
  756
  757#[derive(Clone, Copy, PartialEq, Eq)]
  758pub enum MinimapVisibility {
  759    Disabled,
  760    Enabled {
  761        /// The configuration currently present in the users settings.
  762        setting_configuration: bool,
  763        /// Whether to override the currently set visibility from the users setting.
  764        toggle_override: bool,
  765    },
  766}
  767
  768impl MinimapVisibility {
  769    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  770        if mode.is_full() {
  771            Self::Enabled {
  772                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  773                toggle_override: false,
  774            }
  775        } else {
  776            Self::Disabled
  777        }
  778    }
  779
  780    fn hidden(&self) -> Self {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => Self::Enabled {
  786                setting_configuration,
  787                toggle_override: setting_configuration,
  788            },
  789            Self::Disabled => Self::Disabled,
  790        }
  791    }
  792
  793    fn disabled(&self) -> bool {
  794        matches!(*self, Self::Disabled)
  795    }
  796
  797    fn settings_visibility(&self) -> bool {
  798        match *self {
  799            Self::Enabled {
  800                setting_configuration,
  801                ..
  802            } => setting_configuration,
  803            _ => false,
  804        }
  805    }
  806
  807    fn visible(&self) -> bool {
  808        match *self {
  809            Self::Enabled {
  810                setting_configuration,
  811                toggle_override,
  812            } => setting_configuration ^ toggle_override,
  813            _ => false,
  814        }
  815    }
  816
  817    fn toggle_visibility(&self) -> Self {
  818        match *self {
  819            Self::Enabled {
  820                toggle_override,
  821                setting_configuration,
  822            } => Self::Enabled {
  823                setting_configuration,
  824                toggle_override: !toggle_override,
  825            },
  826            Self::Disabled => Self::Disabled,
  827        }
  828    }
  829}
  830
  831#[derive(Clone, Debug)]
  832struct RunnableTasks {
  833    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  834    offset: multi_buffer::Anchor,
  835    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  836    column: u32,
  837    // Values of all named captures, including those starting with '_'
  838    extra_variables: HashMap<String, String>,
  839    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  840    context_range: Range<BufferOffset>,
  841}
  842
  843impl RunnableTasks {
  844    fn resolve<'a>(
  845        &'a self,
  846        cx: &'a task::TaskContext,
  847    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  848        self.templates.iter().filter_map(|(kind, template)| {
  849            template
  850                .resolve_task(&kind.to_id_base(), cx)
  851                .map(|task| (kind.clone(), task))
  852        })
  853    }
  854}
  855
  856#[derive(Clone)]
  857pub struct ResolvedTasks {
  858    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  859    position: Anchor,
  860}
  861
  862#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  863struct BufferOffset(usize);
  864
  865/// Addons allow storing per-editor state in other crates (e.g. Vim)
  866pub trait Addon: 'static {
  867    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  868
  869    fn render_buffer_header_controls(
  870        &self,
  871        _: &ExcerptInfo,
  872        _: &Window,
  873        _: &App,
  874    ) -> Option<AnyElement> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    inlay_hint_cache: InlayHintCache,
 1126    next_inlay_id: u32,
 1127    next_color_inlay_id: u32,
 1128    _subscriptions: Vec<Subscription>,
 1129    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1130    gutter_dimensions: GutterDimensions,
 1131    style: Option<EditorStyle>,
 1132    text_style_refinement: Option<TextStyleRefinement>,
 1133    next_editor_action_id: EditorActionId,
 1134    editor_actions: Rc<
 1135        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1136    >,
 1137    use_autoclose: bool,
 1138    use_auto_surround: bool,
 1139    auto_replace_emoji_shortcode: bool,
 1140    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1141    show_git_blame_gutter: bool,
 1142    show_git_blame_inline: bool,
 1143    show_git_blame_inline_delay_task: Option<Task<()>>,
 1144    git_blame_inline_enabled: bool,
 1145    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1146    serialize_dirty_buffers: bool,
 1147    show_selection_menu: Option<bool>,
 1148    blame: Option<Entity<GitBlame>>,
 1149    blame_subscription: Option<Subscription>,
 1150    custom_context_menu: Option<
 1151        Box<
 1152            dyn 'static
 1153                + Fn(
 1154                    &mut Self,
 1155                    DisplayPoint,
 1156                    &mut Window,
 1157                    &mut Context<Self>,
 1158                ) -> Option<Entity<ui::ContextMenu>>,
 1159        >,
 1160    >,
 1161    last_bounds: Option<Bounds<Pixels>>,
 1162    last_position_map: Option<Rc<PositionMap>>,
 1163    expect_bounds_change: Option<Bounds<Pixels>>,
 1164    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1165    tasks_update_task: Option<Task<()>>,
 1166    breakpoint_store: Option<Entity<BreakpointStore>>,
 1167    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1168    hovered_diff_hunk_row: Option<DisplayRow>,
 1169    pull_diagnostics_task: Task<()>,
 1170    in_project_search: bool,
 1171    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1172    breadcrumb_header: Option<String>,
 1173    focused_block: Option<FocusedBlock>,
 1174    next_scroll_position: NextScrollCursorCenterTopBottom,
 1175    addons: HashMap<TypeId, Box<dyn Addon>>,
 1176    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1177    load_diff_task: Option<Shared<Task<()>>>,
 1178    /// Whether we are temporarily displaying a diff other than git's
 1179    temporary_diff_override: bool,
 1180    selection_mark_mode: bool,
 1181    toggle_fold_multiple_buffers: Task<()>,
 1182    _scroll_cursor_center_top_bottom_task: Task<()>,
 1183    serialize_selections: Task<()>,
 1184    serialize_folds: Task<()>,
 1185    mouse_cursor_hidden: bool,
 1186    minimap: Option<Entity<Self>>,
 1187    hide_mouse_mode: HideMouseMode,
 1188    pub change_list: ChangeList,
 1189    inline_value_cache: InlineValueCache,
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    folding_newlines: Task<()>,
 1193    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1194}
 1195
 1196#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1197enum NextScrollCursorCenterTopBottom {
 1198    #[default]
 1199    Center,
 1200    Top,
 1201    Bottom,
 1202}
 1203
 1204impl NextScrollCursorCenterTopBottom {
 1205    fn next(&self) -> Self {
 1206        match self {
 1207            Self::Center => Self::Top,
 1208            Self::Top => Self::Bottom,
 1209            Self::Bottom => Self::Center,
 1210        }
 1211    }
 1212}
 1213
 1214#[derive(Clone)]
 1215pub struct EditorSnapshot {
 1216    pub mode: EditorMode,
 1217    show_gutter: bool,
 1218    show_line_numbers: Option<bool>,
 1219    show_git_diff_gutter: Option<bool>,
 1220    show_code_actions: Option<bool>,
 1221    show_runnables: Option<bool>,
 1222    show_breakpoints: Option<bool>,
 1223    git_blame_gutter_max_author_length: Option<usize>,
 1224    pub display_snapshot: DisplaySnapshot,
 1225    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1226    is_focused: bool,
 1227    scroll_anchor: ScrollAnchor,
 1228    ongoing_scroll: OngoingScroll,
 1229    current_line_highlight: CurrentLineHighlight,
 1230    gutter_hovered: bool,
 1231}
 1232
 1233#[derive(Default, Debug, Clone, Copy)]
 1234pub struct GutterDimensions {
 1235    pub left_padding: Pixels,
 1236    pub right_padding: Pixels,
 1237    pub width: Pixels,
 1238    pub margin: Pixels,
 1239    pub git_blame_entries_width: Option<Pixels>,
 1240}
 1241
 1242impl GutterDimensions {
 1243    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1244        Self {
 1245            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1246            ..Default::default()
 1247        }
 1248    }
 1249
 1250    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1251        -cx.text_system().descent(font_id, font_size)
 1252    }
 1253    /// The full width of the space taken up by the gutter.
 1254    pub fn full_width(&self) -> Pixels {
 1255        self.margin + self.width
 1256    }
 1257
 1258    /// The width of the space reserved for the fold indicators,
 1259    /// use alongside 'justify_end' and `gutter_width` to
 1260    /// right align content with the line numbers
 1261    pub fn fold_area_width(&self) -> Pixels {
 1262        self.margin + self.right_padding
 1263    }
 1264}
 1265
 1266struct CharacterDimensions {
 1267    em_width: Pixels,
 1268    em_advance: Pixels,
 1269    line_height: Pixels,
 1270}
 1271
 1272#[derive(Debug)]
 1273pub struct RemoteSelection {
 1274    pub replica_id: ReplicaId,
 1275    pub selection: Selection<Anchor>,
 1276    pub cursor_shape: CursorShape,
 1277    pub collaborator_id: CollaboratorId,
 1278    pub line_mode: bool,
 1279    pub user_name: Option<SharedString>,
 1280    pub color: PlayerColor,
 1281}
 1282
 1283#[derive(Clone, Debug)]
 1284struct SelectionHistoryEntry {
 1285    selections: Arc<[Selection<Anchor>]>,
 1286    select_next_state: Option<SelectNextState>,
 1287    select_prev_state: Option<SelectNextState>,
 1288    add_selections_state: Option<AddSelectionsState>,
 1289}
 1290
 1291#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1292enum SelectionHistoryMode {
 1293    Normal,
 1294    Undoing,
 1295    Redoing,
 1296    Skipping,
 1297}
 1298
 1299#[derive(Clone, PartialEq, Eq, Hash)]
 1300struct HoveredCursor {
 1301    replica_id: u16,
 1302    selection_id: usize,
 1303}
 1304
 1305impl Default for SelectionHistoryMode {
 1306    fn default() -> Self {
 1307        Self::Normal
 1308    }
 1309}
 1310
 1311#[derive(Debug)]
 1312/// SelectionEffects controls the side-effects of updating the selection.
 1313///
 1314/// The default behaviour does "what you mostly want":
 1315/// - it pushes to the nav history if the cursor moved by >10 lines
 1316/// - it re-triggers completion requests
 1317/// - it scrolls to fit
 1318///
 1319/// You might want to modify these behaviours. For example when doing a "jump"
 1320/// like go to definition, we always want to add to nav history; but when scrolling
 1321/// in vim mode we never do.
 1322///
 1323/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1324/// move.
 1325#[derive(Clone)]
 1326pub struct SelectionEffects {
 1327    nav_history: Option<bool>,
 1328    completions: bool,
 1329    scroll: Option<Autoscroll>,
 1330}
 1331
 1332impl Default for SelectionEffects {
 1333    fn default() -> Self {
 1334        Self {
 1335            nav_history: None,
 1336            completions: true,
 1337            scroll: Some(Autoscroll::fit()),
 1338        }
 1339    }
 1340}
 1341impl SelectionEffects {
 1342    pub fn scroll(scroll: Autoscroll) -> Self {
 1343        Self {
 1344            scroll: Some(scroll),
 1345            ..Default::default()
 1346        }
 1347    }
 1348
 1349    pub fn no_scroll() -> Self {
 1350        Self {
 1351            scroll: None,
 1352            ..Default::default()
 1353        }
 1354    }
 1355
 1356    pub fn completions(self, completions: bool) -> Self {
 1357        Self {
 1358            completions,
 1359            ..self
 1360        }
 1361    }
 1362
 1363    pub fn nav_history(self, nav_history: bool) -> Self {
 1364        Self {
 1365            nav_history: Some(nav_history),
 1366            ..self
 1367        }
 1368    }
 1369}
 1370
 1371struct DeferredSelectionEffectsState {
 1372    changed: bool,
 1373    effects: SelectionEffects,
 1374    old_cursor_position: Anchor,
 1375    history_entry: SelectionHistoryEntry,
 1376}
 1377
 1378#[derive(Default)]
 1379struct SelectionHistory {
 1380    #[allow(clippy::type_complexity)]
 1381    selections_by_transaction:
 1382        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1383    mode: SelectionHistoryMode,
 1384    undo_stack: VecDeque<SelectionHistoryEntry>,
 1385    redo_stack: VecDeque<SelectionHistoryEntry>,
 1386}
 1387
 1388impl SelectionHistory {
 1389    #[track_caller]
 1390    fn insert_transaction(
 1391        &mut self,
 1392        transaction_id: TransactionId,
 1393        selections: Arc<[Selection<Anchor>]>,
 1394    ) {
 1395        if selections.is_empty() {
 1396            log::error!(
 1397                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1398                std::panic::Location::caller()
 1399            );
 1400            return;
 1401        }
 1402        self.selections_by_transaction
 1403            .insert(transaction_id, (selections, None));
 1404    }
 1405
 1406    #[allow(clippy::type_complexity)]
 1407    fn transaction(
 1408        &self,
 1409        transaction_id: TransactionId,
 1410    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1411        self.selections_by_transaction.get(&transaction_id)
 1412    }
 1413
 1414    #[allow(clippy::type_complexity)]
 1415    fn transaction_mut(
 1416        &mut self,
 1417        transaction_id: TransactionId,
 1418    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1419        self.selections_by_transaction.get_mut(&transaction_id)
 1420    }
 1421
 1422    fn push(&mut self, entry: SelectionHistoryEntry) {
 1423        if !entry.selections.is_empty() {
 1424            match self.mode {
 1425                SelectionHistoryMode::Normal => {
 1426                    self.push_undo(entry);
 1427                    self.redo_stack.clear();
 1428                }
 1429                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1430                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1431                SelectionHistoryMode::Skipping => {}
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .undo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.undo_stack.push_back(entry);
 1443            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.undo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448
 1449    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1450        if self
 1451            .redo_stack
 1452            .back()
 1453            .is_none_or(|e| e.selections != entry.selections)
 1454        {
 1455            self.redo_stack.push_back(entry);
 1456            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1457                self.redo_stack.pop_front();
 1458            }
 1459        }
 1460    }
 1461}
 1462
 1463#[derive(Clone, Copy)]
 1464pub struct RowHighlightOptions {
 1465    pub autoscroll: bool,
 1466    pub include_gutter: bool,
 1467}
 1468
 1469impl Default for RowHighlightOptions {
 1470    fn default() -> Self {
 1471        Self {
 1472            autoscroll: Default::default(),
 1473            include_gutter: true,
 1474        }
 1475    }
 1476}
 1477
 1478struct RowHighlight {
 1479    index: usize,
 1480    range: Range<Anchor>,
 1481    color: Hsla,
 1482    options: RowHighlightOptions,
 1483    type_id: TypeId,
 1484}
 1485
 1486#[derive(Clone, Debug)]
 1487struct AddSelectionsState {
 1488    groups: Vec<AddSelectionsGroup>,
 1489}
 1490
 1491#[derive(Clone, Debug)]
 1492struct AddSelectionsGroup {
 1493    above: bool,
 1494    stack: Vec<usize>,
 1495}
 1496
 1497#[derive(Clone)]
 1498struct SelectNextState {
 1499    query: AhoCorasick,
 1500    wordwise: bool,
 1501    done: bool,
 1502}
 1503
 1504impl std::fmt::Debug for SelectNextState {
 1505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1506        f.debug_struct(std::any::type_name::<Self>())
 1507            .field("wordwise", &self.wordwise)
 1508            .field("done", &self.done)
 1509            .finish()
 1510    }
 1511}
 1512
 1513#[derive(Debug)]
 1514struct AutocloseRegion {
 1515    selection_id: usize,
 1516    range: Range<Anchor>,
 1517    pair: BracketPair,
 1518}
 1519
 1520#[derive(Debug)]
 1521struct SnippetState {
 1522    ranges: Vec<Vec<Range<Anchor>>>,
 1523    active_index: usize,
 1524    choices: Vec<Option<Vec<String>>>,
 1525}
 1526
 1527#[doc(hidden)]
 1528pub struct RenameState {
 1529    pub range: Range<Anchor>,
 1530    pub old_name: Arc<str>,
 1531    pub editor: Entity<Editor>,
 1532    block_id: CustomBlockId,
 1533}
 1534
 1535struct InvalidationStack<T>(Vec<T>);
 1536
 1537struct RegisteredEditPredictionProvider {
 1538    provider: Arc<dyn EditPredictionProviderHandle>,
 1539    _subscription: Subscription,
 1540}
 1541
 1542#[derive(Debug, PartialEq, Eq)]
 1543pub struct ActiveDiagnosticGroup {
 1544    pub active_range: Range<Anchor>,
 1545    pub active_message: String,
 1546    pub group_id: usize,
 1547    pub blocks: HashSet<CustomBlockId>,
 1548}
 1549
 1550#[derive(Debug, PartialEq, Eq)]
 1551
 1552pub(crate) enum ActiveDiagnostic {
 1553    None,
 1554    All,
 1555    Group(ActiveDiagnosticGroup),
 1556}
 1557
 1558#[derive(Serialize, Deserialize, Clone, Debug)]
 1559pub struct ClipboardSelection {
 1560    /// The number of bytes in this selection.
 1561    pub len: usize,
 1562    /// Whether this was a full-line selection.
 1563    pub is_entire_line: bool,
 1564    /// The indentation of the first line when this content was originally copied.
 1565    pub first_line_indent: u32,
 1566}
 1567
 1568// selections, scroll behavior, was newest selection reversed
 1569type SelectSyntaxNodeHistoryState = (
 1570    Box<[Selection<usize>]>,
 1571    SelectSyntaxNodeScrollBehavior,
 1572    bool,
 1573);
 1574
 1575#[derive(Default)]
 1576struct SelectSyntaxNodeHistory {
 1577    stack: Vec<SelectSyntaxNodeHistoryState>,
 1578    // disable temporarily to allow changing selections without losing the stack
 1579    pub disable_clearing: bool,
 1580}
 1581
 1582impl SelectSyntaxNodeHistory {
 1583    pub fn try_clear(&mut self) {
 1584        if !self.disable_clearing {
 1585            self.stack.clear();
 1586        }
 1587    }
 1588
 1589    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1590        self.stack.push(selection);
 1591    }
 1592
 1593    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1594        self.stack.pop()
 1595    }
 1596}
 1597
 1598enum SelectSyntaxNodeScrollBehavior {
 1599    CursorTop,
 1600    FitSelection,
 1601    CursorBottom,
 1602}
 1603
 1604#[derive(Debug)]
 1605pub(crate) struct NavigationData {
 1606    cursor_anchor: Anchor,
 1607    cursor_position: Point,
 1608    scroll_anchor: ScrollAnchor,
 1609    scroll_top_row: u32,
 1610}
 1611
 1612#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1613pub enum GotoDefinitionKind {
 1614    Symbol,
 1615    Declaration,
 1616    Type,
 1617    Implementation,
 1618}
 1619
 1620#[derive(Debug, Clone)]
 1621enum InlayHintRefreshReason {
 1622    ModifiersChanged(bool),
 1623    Toggle(bool),
 1624    SettingsChange(InlayHintSettings),
 1625    NewLinesShown,
 1626    BufferEdited(HashSet<Arc<Language>>),
 1627    RefreshRequested,
 1628    ExcerptsRemoved(Vec<ExcerptId>),
 1629}
 1630
 1631impl InlayHintRefreshReason {
 1632    fn description(&self) -> &'static str {
 1633        match self {
 1634            Self::ModifiersChanged(_) => "modifiers changed",
 1635            Self::Toggle(_) => "toggle",
 1636            Self::SettingsChange(_) => "settings change",
 1637            Self::NewLinesShown => "new lines shown",
 1638            Self::BufferEdited(_) => "buffer edited",
 1639            Self::RefreshRequested => "refresh requested",
 1640            Self::ExcerptsRemoved(_) => "excerpts removed",
 1641        }
 1642    }
 1643}
 1644
 1645pub enum FormatTarget {
 1646    Buffers(HashSet<Entity<Buffer>>),
 1647    Ranges(Vec<Range<MultiBufferPoint>>),
 1648}
 1649
 1650pub(crate) struct FocusedBlock {
 1651    id: BlockId,
 1652    focus_handle: WeakFocusHandle,
 1653}
 1654
 1655#[derive(Clone)]
 1656enum JumpData {
 1657    MultiBufferRow {
 1658        row: MultiBufferRow,
 1659        line_offset_from_top: u32,
 1660    },
 1661    MultiBufferPoint {
 1662        excerpt_id: ExcerptId,
 1663        position: Point,
 1664        anchor: text::Anchor,
 1665        line_offset_from_top: u32,
 1666    },
 1667}
 1668
 1669pub enum MultibufferSelectionMode {
 1670    First,
 1671    All,
 1672}
 1673
 1674#[derive(Clone, Copy, Debug, Default)]
 1675pub struct RewrapOptions {
 1676    pub override_language_settings: bool,
 1677    pub preserve_existing_whitespace: bool,
 1678}
 1679
 1680impl Editor {
 1681    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1685    }
 1686
 1687    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1688        let buffer = cx.new(|cx| Buffer::local("", cx));
 1689        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1690        Self::new(EditorMode::full(), buffer, None, window, cx)
 1691    }
 1692
 1693    pub fn auto_height(
 1694        min_lines: usize,
 1695        max_lines: usize,
 1696        window: &mut Window,
 1697        cx: &mut Context<Self>,
 1698    ) -> Self {
 1699        let buffer = cx.new(|cx| Buffer::local("", cx));
 1700        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1701        Self::new(
 1702            EditorMode::AutoHeight {
 1703                min_lines,
 1704                max_lines: Some(max_lines),
 1705            },
 1706            buffer,
 1707            None,
 1708            window,
 1709            cx,
 1710        )
 1711    }
 1712
 1713    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1714    /// The editor grows as tall as needed to fit its content.
 1715    pub fn auto_height_unbounded(
 1716        min_lines: usize,
 1717        window: &mut Window,
 1718        cx: &mut Context<Self>,
 1719    ) -> Self {
 1720        let buffer = cx.new(|cx| Buffer::local("", cx));
 1721        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1722        Self::new(
 1723            EditorMode::AutoHeight {
 1724                min_lines,
 1725                max_lines: None,
 1726            },
 1727            buffer,
 1728            None,
 1729            window,
 1730            cx,
 1731        )
 1732    }
 1733
 1734    pub fn for_buffer(
 1735        buffer: Entity<Buffer>,
 1736        project: Option<Entity<Project>>,
 1737        window: &mut Window,
 1738        cx: &mut Context<Self>,
 1739    ) -> Self {
 1740        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1741        Self::new(EditorMode::full(), buffer, project, window, cx)
 1742    }
 1743
 1744    pub fn for_multibuffer(
 1745        buffer: Entity<MultiBuffer>,
 1746        project: Option<Entity<Project>>,
 1747        window: &mut Window,
 1748        cx: &mut Context<Self>,
 1749    ) -> Self {
 1750        Self::new(EditorMode::full(), buffer, project, window, cx)
 1751    }
 1752
 1753    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1754        let mut clone = Self::new(
 1755            self.mode.clone(),
 1756            self.buffer.clone(),
 1757            self.project.clone(),
 1758            window,
 1759            cx,
 1760        );
 1761        self.display_map.update(cx, |display_map, cx| {
 1762            let snapshot = display_map.snapshot(cx);
 1763            clone.display_map.update(cx, |display_map, cx| {
 1764                display_map.set_state(&snapshot, cx);
 1765            });
 1766        });
 1767        clone.folds_did_change(cx);
 1768        clone.selections.clone_state(&self.selections);
 1769        clone.scroll_manager.clone_state(&self.scroll_manager);
 1770        clone.searchable = self.searchable;
 1771        clone.read_only = self.read_only;
 1772        clone
 1773    }
 1774
 1775    pub fn new(
 1776        mode: EditorMode,
 1777        buffer: Entity<MultiBuffer>,
 1778        project: Option<Entity<Project>>,
 1779        window: &mut Window,
 1780        cx: &mut Context<Self>,
 1781    ) -> Self {
 1782        Editor::new_internal(mode, buffer, project, None, window, cx)
 1783    }
 1784
 1785    fn new_internal(
 1786        mode: EditorMode,
 1787        buffer: Entity<MultiBuffer>,
 1788        project: Option<Entity<Project>>,
 1789        display_map: Option<Entity<DisplayMap>>,
 1790        window: &mut Window,
 1791        cx: &mut Context<Self>,
 1792    ) -> Self {
 1793        debug_assert!(
 1794            display_map.is_none() || mode.is_minimap(),
 1795            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1796        );
 1797
 1798        let full_mode = mode.is_full();
 1799        let is_minimap = mode.is_minimap();
 1800        let diagnostics_max_severity = if full_mode {
 1801            EditorSettings::get_global(cx)
 1802                .diagnostics_max_severity
 1803                .unwrap_or(DiagnosticSeverity::Hint)
 1804        } else {
 1805            DiagnosticSeverity::Off
 1806        };
 1807        let style = window.text_style();
 1808        let font_size = style.font_size.to_pixels(window.rem_size());
 1809        let editor = cx.entity().downgrade();
 1810        let fold_placeholder = FoldPlaceholder {
 1811            constrain_width: false,
 1812            render: Arc::new(move |fold_id, fold_range, cx| {
 1813                let editor = editor.clone();
 1814                div()
 1815                    .id(fold_id)
 1816                    .bg(cx.theme().colors().ghost_element_background)
 1817                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1818                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1819                    .rounded_xs()
 1820                    .size_full()
 1821                    .cursor_pointer()
 1822                    .child("")
 1823                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1824                    .on_click(move |_, _window, cx| {
 1825                        editor
 1826                            .update(cx, |editor, cx| {
 1827                                editor.unfold_ranges(
 1828                                    &[fold_range.start..fold_range.end],
 1829                                    true,
 1830                                    false,
 1831                                    cx,
 1832                                );
 1833                                cx.stop_propagation();
 1834                            })
 1835                            .ok();
 1836                    })
 1837                    .into_any()
 1838            }),
 1839            merge_adjacent: true,
 1840            ..FoldPlaceholder::default()
 1841        };
 1842        let display_map = display_map.unwrap_or_else(|| {
 1843            cx.new(|cx| {
 1844                DisplayMap::new(
 1845                    buffer.clone(),
 1846                    style.font(),
 1847                    font_size,
 1848                    None,
 1849                    FILE_HEADER_HEIGHT,
 1850                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1851                    fold_placeholder,
 1852                    diagnostics_max_severity,
 1853                    cx,
 1854                )
 1855            })
 1856        });
 1857
 1858        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1859
 1860        let blink_manager = cx.new(|cx| {
 1861            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1862            if is_minimap {
 1863                blink_manager.disable(cx);
 1864            }
 1865            blink_manager
 1866        });
 1867
 1868        let soft_wrap_mode_override =
 1869            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1870
 1871        let mut project_subscriptions = Vec::new();
 1872        if full_mode && let Some(project) = project.as_ref() {
 1873            project_subscriptions.push(cx.subscribe_in(
 1874                project,
 1875                window,
 1876                |editor, _, event, window, cx| match event {
 1877                    project::Event::RefreshCodeLens => {
 1878                        // we always query lens with actions, without storing them, always refreshing them
 1879                    }
 1880                    project::Event::RefreshInlayHints => {
 1881                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1882                    }
 1883                    project::Event::LanguageServerAdded(..)
 1884                    | project::Event::LanguageServerRemoved(..) => {
 1885                        if editor.tasks_update_task.is_none() {
 1886                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1887                        }
 1888                    }
 1889                    project::Event::SnippetEdit(id, snippet_edits) => {
 1890                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1891                            let focus_handle = editor.focus_handle(cx);
 1892                            if focus_handle.is_focused(window) {
 1893                                let snapshot = buffer.read(cx).snapshot();
 1894                                for (range, snippet) in snippet_edits {
 1895                                    let editor_range =
 1896                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1897                                    editor
 1898                                        .insert_snippet(
 1899                                            &[editor_range],
 1900                                            snippet.clone(),
 1901                                            window,
 1902                                            cx,
 1903                                        )
 1904                                        .ok();
 1905                                }
 1906                            }
 1907                        }
 1908                    }
 1909                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1910                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1911                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1912                        }
 1913                    }
 1914
 1915                    project::Event::EntryRenamed(transaction) => {
 1916                        let Some(workspace) = editor.workspace() else {
 1917                            return;
 1918                        };
 1919                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1920                        else {
 1921                            return;
 1922                        };
 1923                        if active_editor.entity_id() == cx.entity_id() {
 1924                            let edited_buffers_already_open = {
 1925                                let other_editors: Vec<Entity<Editor>> = workspace
 1926                                    .read(cx)
 1927                                    .panes()
 1928                                    .iter()
 1929                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1930                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1931                                    .collect();
 1932
 1933                                transaction.0.keys().all(|buffer| {
 1934                                    other_editors.iter().any(|editor| {
 1935                                        let multi_buffer = editor.read(cx).buffer();
 1936                                        multi_buffer.read(cx).is_singleton()
 1937                                            && multi_buffer.read(cx).as_singleton().map_or(
 1938                                                false,
 1939                                                |singleton| {
 1940                                                    singleton.entity_id() == buffer.entity_id()
 1941                                                },
 1942                                            )
 1943                                    })
 1944                                })
 1945                            };
 1946
 1947                            if !edited_buffers_already_open {
 1948                                let workspace = workspace.downgrade();
 1949                                let transaction = transaction.clone();
 1950                                cx.defer_in(window, move |_, window, cx| {
 1951                                    cx.spawn_in(window, async move |editor, cx| {
 1952                                        Self::open_project_transaction(
 1953                                            &editor,
 1954                                            workspace,
 1955                                            transaction,
 1956                                            "Rename".to_string(),
 1957                                            cx,
 1958                                        )
 1959                                        .await
 1960                                        .ok()
 1961                                    })
 1962                                    .detach();
 1963                                });
 1964                            }
 1965                        }
 1966                    }
 1967
 1968                    _ => {}
 1969                },
 1970            ));
 1971            if let Some(task_inventory) = project
 1972                .read(cx)
 1973                .task_store()
 1974                .read(cx)
 1975                .task_inventory()
 1976                .cloned()
 1977            {
 1978                project_subscriptions.push(cx.observe_in(
 1979                    &task_inventory,
 1980                    window,
 1981                    |editor, _, window, cx| {
 1982                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1983                    },
 1984                ));
 1985            };
 1986
 1987            project_subscriptions.push(cx.subscribe_in(
 1988                &project.read(cx).breakpoint_store(),
 1989                window,
 1990                |editor, _, event, window, cx| match event {
 1991                    BreakpointStoreEvent::ClearDebugLines => {
 1992                        editor.clear_row_highlights::<ActiveDebugLine>();
 1993                        editor.refresh_inline_values(cx);
 1994                    }
 1995                    BreakpointStoreEvent::SetDebugLine => {
 1996                        if editor.go_to_active_debug_line(window, cx) {
 1997                            cx.stop_propagation();
 1998                        }
 1999
 2000                        editor.refresh_inline_values(cx);
 2001                    }
 2002                    _ => {}
 2003                },
 2004            ));
 2005            let git_store = project.read(cx).git_store().clone();
 2006            let project = project.clone();
 2007            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2008                if let GitStoreEvent::RepositoryUpdated(
 2009                    _,
 2010                    RepositoryEvent::Updated {
 2011                        new_instance: true, ..
 2012                    },
 2013                    _,
 2014                ) = event
 2015                {
 2016                    this.load_diff_task = Some(
 2017                        update_uncommitted_diff_for_buffer(
 2018                            cx.entity(),
 2019                            &project,
 2020                            this.buffer.read(cx).all_buffers(),
 2021                            this.buffer.clone(),
 2022                            cx,
 2023                        )
 2024                        .shared(),
 2025                    );
 2026                }
 2027            }));
 2028        }
 2029
 2030        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2031
 2032        let inlay_hint_settings =
 2033            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2034        let focus_handle = cx.focus_handle();
 2035        if !is_minimap {
 2036            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2037                .detach();
 2038            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2039                .detach();
 2040            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2041                .detach();
 2042            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2043                .detach();
 2044            cx.observe_pending_input(window, Self::observe_pending_input)
 2045                .detach();
 2046        }
 2047
 2048        let show_indent_guides =
 2049            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2050                Some(false)
 2051            } else {
 2052                None
 2053            };
 2054
 2055        let breakpoint_store = match (&mode, project.as_ref()) {
 2056            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2057            _ => None,
 2058        };
 2059
 2060        let mut code_action_providers = Vec::new();
 2061        let mut load_uncommitted_diff = None;
 2062        if let Some(project) = project.clone() {
 2063            load_uncommitted_diff = Some(
 2064                update_uncommitted_diff_for_buffer(
 2065                    cx.entity(),
 2066                    &project,
 2067                    buffer.read(cx).all_buffers(),
 2068                    buffer.clone(),
 2069                    cx,
 2070                )
 2071                .shared(),
 2072            );
 2073            code_action_providers.push(Rc::new(project) as Rc<_>);
 2074        }
 2075
 2076        let mut editor = Self {
 2077            focus_handle,
 2078            show_cursor_when_unfocused: false,
 2079            last_focused_descendant: None,
 2080            buffer: buffer.clone(),
 2081            display_map: display_map.clone(),
 2082            placeholder_display_map: None,
 2083            selections,
 2084            scroll_manager: ScrollManager::new(cx),
 2085            columnar_selection_state: None,
 2086            add_selections_state: None,
 2087            select_next_state: None,
 2088            select_prev_state: None,
 2089            selection_history: SelectionHistory::default(),
 2090            defer_selection_effects: false,
 2091            deferred_selection_effects_state: None,
 2092            autoclose_regions: Vec::new(),
 2093            snippet_stack: InvalidationStack::default(),
 2094            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2095            ime_transaction: None,
 2096            active_diagnostics: ActiveDiagnostic::None,
 2097            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2098            inline_diagnostics_update: Task::ready(()),
 2099            inline_diagnostics: Vec::new(),
 2100            soft_wrap_mode_override,
 2101            diagnostics_max_severity,
 2102            hard_wrap: None,
 2103            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2104            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2105            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2106            project,
 2107            blink_manager: blink_manager.clone(),
 2108            show_local_selections: true,
 2109            show_scrollbars: ScrollbarAxes {
 2110                horizontal: full_mode,
 2111                vertical: full_mode,
 2112            },
 2113            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2114            offset_content: !matches!(mode, EditorMode::SingleLine),
 2115            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2116            show_gutter: full_mode,
 2117            show_line_numbers: (!full_mode).then_some(false),
 2118            use_relative_line_numbers: None,
 2119            disable_expand_excerpt_buttons: !full_mode,
 2120            show_git_diff_gutter: None,
 2121            show_code_actions: None,
 2122            show_runnables: None,
 2123            show_breakpoints: None,
 2124            show_wrap_guides: None,
 2125            show_indent_guides,
 2126            highlight_order: 0,
 2127            highlighted_rows: HashMap::default(),
 2128            background_highlights: HashMap::default(),
 2129            gutter_highlights: HashMap::default(),
 2130            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2131            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2132            nav_history: None,
 2133            context_menu: RefCell::new(None),
 2134            context_menu_options: None,
 2135            mouse_context_menu: None,
 2136            completion_tasks: Vec::new(),
 2137            inline_blame_popover: None,
 2138            inline_blame_popover_show_task: None,
 2139            signature_help_state: SignatureHelpState::default(),
 2140            auto_signature_help: None,
 2141            find_all_references_task_sources: Vec::new(),
 2142            next_completion_id: 0,
 2143            next_inlay_id: 0,
 2144            code_action_providers,
 2145            available_code_actions: None,
 2146            code_actions_task: None,
 2147            quick_selection_highlight_task: None,
 2148            debounced_selection_highlight_task: None,
 2149            document_highlights_task: None,
 2150            linked_editing_range_task: None,
 2151            pending_rename: None,
 2152            searchable: !is_minimap,
 2153            cursor_shape: EditorSettings::get_global(cx)
 2154                .cursor_shape
 2155                .unwrap_or_default(),
 2156            current_line_highlight: None,
 2157            autoindent_mode: Some(AutoindentMode::EachLine),
 2158            collapse_matches: false,
 2159            workspace: None,
 2160            input_enabled: !is_minimap,
 2161            use_modal_editing: full_mode,
 2162            read_only: is_minimap,
 2163            use_autoclose: true,
 2164            use_auto_surround: true,
 2165            auto_replace_emoji_shortcode: false,
 2166            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2167            leader_id: None,
 2168            remote_id: None,
 2169            hover_state: HoverState::default(),
 2170            pending_mouse_down: None,
 2171            hovered_link_state: None,
 2172            edit_prediction_provider: None,
 2173            active_edit_prediction: None,
 2174            stale_edit_prediction_in_menu: None,
 2175            edit_prediction_preview: EditPredictionPreview::Inactive {
 2176                released_too_fast: false,
 2177            },
 2178            inline_diagnostics_enabled: full_mode,
 2179            diagnostics_enabled: full_mode,
 2180            word_completions_enabled: full_mode,
 2181            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2182            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2183            gutter_hovered: false,
 2184            pixel_position_of_newest_cursor: None,
 2185            last_bounds: None,
 2186            last_position_map: None,
 2187            expect_bounds_change: None,
 2188            gutter_dimensions: GutterDimensions::default(),
 2189            style: None,
 2190            show_cursor_names: false,
 2191            hovered_cursors: HashMap::default(),
 2192            next_editor_action_id: EditorActionId::default(),
 2193            editor_actions: Rc::default(),
 2194            edit_predictions_hidden_for_vim_mode: false,
 2195            show_edit_predictions_override: None,
 2196            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2197            edit_prediction_settings: EditPredictionSettings::Disabled,
 2198            edit_prediction_indent_conflict: false,
 2199            edit_prediction_requires_modifier_in_indent_conflict: true,
 2200            custom_context_menu: None,
 2201            show_git_blame_gutter: false,
 2202            show_git_blame_inline: false,
 2203            show_selection_menu: None,
 2204            show_git_blame_inline_delay_task: None,
 2205            git_blame_inline_enabled: full_mode
 2206                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2207            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2208            serialize_dirty_buffers: !is_minimap
 2209                && ProjectSettings::get_global(cx)
 2210                    .session
 2211                    .restore_unsaved_buffers,
 2212            blame: None,
 2213            blame_subscription: None,
 2214            tasks: BTreeMap::default(),
 2215
 2216            breakpoint_store,
 2217            gutter_breakpoint_indicator: (None, None),
 2218            hovered_diff_hunk_row: None,
 2219            _subscriptions: (!is_minimap)
 2220                .then(|| {
 2221                    vec![
 2222                        cx.observe(&buffer, Self::on_buffer_changed),
 2223                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2224                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2225                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2226                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2227                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2228                        cx.observe_window_activation(window, |editor, window, cx| {
 2229                            let active = window.is_window_active();
 2230                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2231                                if active {
 2232                                    blink_manager.enable(cx);
 2233                                } else {
 2234                                    blink_manager.disable(cx);
 2235                                }
 2236                            });
 2237                            if active {
 2238                                editor.show_mouse_cursor(cx);
 2239                            }
 2240                        }),
 2241                    ]
 2242                })
 2243                .unwrap_or_default(),
 2244            tasks_update_task: None,
 2245            pull_diagnostics_task: Task::ready(()),
 2246            colors: None,
 2247            next_color_inlay_id: 0,
 2248            linked_edit_ranges: Default::default(),
 2249            in_project_search: false,
 2250            previous_search_ranges: None,
 2251            breadcrumb_header: None,
 2252            focused_block: None,
 2253            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2254            addons: HashMap::default(),
 2255            registered_buffers: HashMap::default(),
 2256            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2257            selection_mark_mode: false,
 2258            toggle_fold_multiple_buffers: Task::ready(()),
 2259            serialize_selections: Task::ready(()),
 2260            serialize_folds: Task::ready(()),
 2261            text_style_refinement: None,
 2262            load_diff_task: load_uncommitted_diff,
 2263            temporary_diff_override: false,
 2264            mouse_cursor_hidden: false,
 2265            minimap: None,
 2266            hide_mouse_mode: EditorSettings::get_global(cx)
 2267                .hide_mouse
 2268                .unwrap_or_default(),
 2269            change_list: ChangeList::new(),
 2270            mode,
 2271            selection_drag_state: SelectionDragState::None,
 2272            folding_newlines: Task::ready(()),
 2273            lookup_key: None,
 2274        };
 2275
 2276        if is_minimap {
 2277            return editor;
 2278        }
 2279
 2280        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2281            editor
 2282                ._subscriptions
 2283                .push(cx.observe(breakpoints, |_, _, cx| {
 2284                    cx.notify();
 2285                }));
 2286        }
 2287        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2288        editor._subscriptions.extend(project_subscriptions);
 2289
 2290        editor._subscriptions.push(cx.subscribe_in(
 2291            &cx.entity(),
 2292            window,
 2293            |editor, _, e: &EditorEvent, window, cx| match e {
 2294                EditorEvent::ScrollPositionChanged { local, .. } => {
 2295                    if *local {
 2296                        let new_anchor = editor.scroll_manager.anchor();
 2297                        let snapshot = editor.snapshot(window, cx);
 2298                        editor.update_restoration_data(cx, move |data| {
 2299                            data.scroll_position = (
 2300                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2301                                new_anchor.offset,
 2302                            );
 2303                        });
 2304                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2305                        editor.inline_blame_popover.take();
 2306                    }
 2307                }
 2308                EditorEvent::Edited { .. } => {
 2309                    if !vim_enabled(cx) {
 2310                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2311                        let pop_state = editor
 2312                            .change_list
 2313                            .last()
 2314                            .map(|previous| {
 2315                                previous.len() == selections.len()
 2316                                    && previous.iter().enumerate().all(|(ix, p)| {
 2317                                        p.to_display_point(&map).row()
 2318                                            == selections[ix].head().row()
 2319                                    })
 2320                            })
 2321                            .unwrap_or(false);
 2322                        let new_positions = selections
 2323                            .into_iter()
 2324                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2325                            .collect();
 2326                        editor
 2327                            .change_list
 2328                            .push_to_change_list(pop_state, new_positions);
 2329                    }
 2330                }
 2331                _ => (),
 2332            },
 2333        ));
 2334
 2335        if let Some(dap_store) = editor
 2336            .project
 2337            .as_ref()
 2338            .map(|project| project.read(cx).dap_store())
 2339        {
 2340            let weak_editor = cx.weak_entity();
 2341
 2342            editor
 2343                ._subscriptions
 2344                .push(
 2345                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2346                        let session_entity = cx.entity();
 2347                        weak_editor
 2348                            .update(cx, |editor, cx| {
 2349                                editor._subscriptions.push(
 2350                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2351                                );
 2352                            })
 2353                            .ok();
 2354                    }),
 2355                );
 2356
 2357            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2358                editor
 2359                    ._subscriptions
 2360                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2361            }
 2362        }
 2363
 2364        // skip adding the initial selection to selection history
 2365        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2366        editor.end_selection(window, cx);
 2367        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2368
 2369        editor.scroll_manager.show_scrollbars(window, cx);
 2370        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2371
 2372        if full_mode {
 2373            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2374            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2375
 2376            if editor.git_blame_inline_enabled {
 2377                editor.start_git_blame_inline(false, window, cx);
 2378            }
 2379
 2380            editor.go_to_active_debug_line(window, cx);
 2381
 2382            if let Some(buffer) = buffer.read(cx).as_singleton()
 2383                && let Some(project) = editor.project()
 2384            {
 2385                let handle = project.update(cx, |project, cx| {
 2386                    project.register_buffer_with_language_servers(&buffer, cx)
 2387                });
 2388                editor
 2389                    .registered_buffers
 2390                    .insert(buffer.read(cx).remote_id(), handle);
 2391            }
 2392
 2393            editor.minimap =
 2394                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2395            editor.colors = Some(LspColorData::new(cx));
 2396            editor.update_lsp_data(false, None, window, cx);
 2397        }
 2398
 2399        if editor.mode.is_full() {
 2400            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2401        }
 2402
 2403        editor
 2404    }
 2405
 2406    pub fn deploy_mouse_context_menu(
 2407        &mut self,
 2408        position: gpui::Point<Pixels>,
 2409        context_menu: Entity<ContextMenu>,
 2410        window: &mut Window,
 2411        cx: &mut Context<Self>,
 2412    ) {
 2413        self.mouse_context_menu = Some(MouseContextMenu::new(
 2414            self,
 2415            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2416            context_menu,
 2417            window,
 2418            cx,
 2419        ));
 2420    }
 2421
 2422    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2423        self.mouse_context_menu
 2424            .as_ref()
 2425            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2426    }
 2427
 2428    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2429        if self
 2430            .selections
 2431            .pending_anchor()
 2432            .is_some_and(|pending_selection| {
 2433                let snapshot = self.buffer().read(cx).snapshot(cx);
 2434                pending_selection.range().includes(range, &snapshot)
 2435            })
 2436        {
 2437            return true;
 2438        }
 2439
 2440        self.selections
 2441            .disjoint_in_range::<usize>(range.clone(), cx)
 2442            .into_iter()
 2443            .any(|selection| {
 2444                // This is needed to cover a corner case, if we just check for an existing
 2445                // selection in the fold range, having a cursor at the start of the fold
 2446                // marks it as selected. Non-empty selections don't cause this.
 2447                let length = selection.end - selection.start;
 2448                length > 0
 2449            })
 2450    }
 2451
 2452    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2453        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2454    }
 2455
 2456    fn key_context_internal(
 2457        &self,
 2458        has_active_edit_prediction: bool,
 2459        window: &Window,
 2460        cx: &App,
 2461    ) -> KeyContext {
 2462        let mut key_context = KeyContext::new_with_defaults();
 2463        key_context.add("Editor");
 2464        let mode = match self.mode {
 2465            EditorMode::SingleLine => "single_line",
 2466            EditorMode::AutoHeight { .. } => "auto_height",
 2467            EditorMode::Minimap { .. } => "minimap",
 2468            EditorMode::Full { .. } => "full",
 2469        };
 2470
 2471        if EditorSettings::jupyter_enabled(cx) {
 2472            key_context.add("jupyter");
 2473        }
 2474
 2475        key_context.set("mode", mode);
 2476        if self.pending_rename.is_some() {
 2477            key_context.add("renaming");
 2478        }
 2479
 2480        match self.context_menu.borrow().as_ref() {
 2481            Some(CodeContextMenu::Completions(menu)) => {
 2482                if menu.visible() {
 2483                    key_context.add("menu");
 2484                    key_context.add("showing_completions");
 2485                }
 2486            }
 2487            Some(CodeContextMenu::CodeActions(menu)) => {
 2488                if menu.visible() {
 2489                    key_context.add("menu");
 2490                    key_context.add("showing_code_actions")
 2491                }
 2492            }
 2493            None => {}
 2494        }
 2495
 2496        if self.signature_help_state.has_multiple_signatures() {
 2497            key_context.add("showing_signature_help");
 2498        }
 2499
 2500        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2501        if !self.focus_handle(cx).contains_focused(window, cx)
 2502            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2503        {
 2504            for addon in self.addons.values() {
 2505                addon.extend_key_context(&mut key_context, cx)
 2506            }
 2507        }
 2508
 2509        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2510            if let Some(extension) = singleton_buffer
 2511                .read(cx)
 2512                .file()
 2513                .and_then(|file| file.path().extension())
 2514            {
 2515                key_context.set("extension", extension.to_string());
 2516            }
 2517        } else {
 2518            key_context.add("multibuffer");
 2519        }
 2520
 2521        if has_active_edit_prediction {
 2522            if self.edit_prediction_in_conflict() {
 2523                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2524            } else {
 2525                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2526                key_context.add("copilot_suggestion");
 2527            }
 2528        }
 2529
 2530        if self.selection_mark_mode {
 2531            key_context.add("selection_mode");
 2532        }
 2533
 2534        key_context
 2535    }
 2536
 2537    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2538        self.last_bounds.as_ref()
 2539    }
 2540
 2541    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2542        if self.mouse_cursor_hidden {
 2543            self.mouse_cursor_hidden = false;
 2544            cx.notify();
 2545        }
 2546    }
 2547
 2548    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2549        let hide_mouse_cursor = match origin {
 2550            HideMouseCursorOrigin::TypingAction => {
 2551                matches!(
 2552                    self.hide_mouse_mode,
 2553                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2554                )
 2555            }
 2556            HideMouseCursorOrigin::MovementAction => {
 2557                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2558            }
 2559        };
 2560        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2561            self.mouse_cursor_hidden = hide_mouse_cursor;
 2562            cx.notify();
 2563        }
 2564    }
 2565
 2566    pub fn edit_prediction_in_conflict(&self) -> bool {
 2567        if !self.show_edit_predictions_in_menu() {
 2568            return false;
 2569        }
 2570
 2571        let showing_completions = self
 2572            .context_menu
 2573            .borrow()
 2574            .as_ref()
 2575            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2576
 2577        showing_completions
 2578            || self.edit_prediction_requires_modifier()
 2579            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2580            // bindings to insert tab characters.
 2581            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2582    }
 2583
 2584    pub fn accept_edit_prediction_keybind(
 2585        &self,
 2586        accept_partial: bool,
 2587        window: &Window,
 2588        cx: &App,
 2589    ) -> AcceptEditPredictionBinding {
 2590        let key_context = self.key_context_internal(true, window, cx);
 2591        let in_conflict = self.edit_prediction_in_conflict();
 2592
 2593        let bindings = if accept_partial {
 2594            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2595        } else {
 2596            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2597        };
 2598
 2599        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2600        // just the first one.
 2601        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2602            !in_conflict
 2603                || binding
 2604                    .keystrokes()
 2605                    .first()
 2606                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2607        }))
 2608    }
 2609
 2610    pub fn new_file(
 2611        workspace: &mut Workspace,
 2612        _: &workspace::NewFile,
 2613        window: &mut Window,
 2614        cx: &mut Context<Workspace>,
 2615    ) {
 2616        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2617            "Failed to create buffer",
 2618            window,
 2619            cx,
 2620            |e, _, _| match e.error_code() {
 2621                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2622                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2623                e.error_tag("required").unwrap_or("the latest version")
 2624            )),
 2625                _ => None,
 2626            },
 2627        );
 2628    }
 2629
 2630    pub fn new_in_workspace(
 2631        workspace: &mut Workspace,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) -> Task<Result<Entity<Editor>>> {
 2635        let project = workspace.project().clone();
 2636        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2637
 2638        cx.spawn_in(window, async move |workspace, cx| {
 2639            let buffer = create.await?;
 2640            workspace.update_in(cx, |workspace, window, cx| {
 2641                let editor =
 2642                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2643                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2644                editor
 2645            })
 2646        })
 2647    }
 2648
 2649    fn new_file_vertical(
 2650        workspace: &mut Workspace,
 2651        _: &workspace::NewFileSplitVertical,
 2652        window: &mut Window,
 2653        cx: &mut Context<Workspace>,
 2654    ) {
 2655        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2656    }
 2657
 2658    fn new_file_horizontal(
 2659        workspace: &mut Workspace,
 2660        _: &workspace::NewFileSplitHorizontal,
 2661        window: &mut Window,
 2662        cx: &mut Context<Workspace>,
 2663    ) {
 2664        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2665    }
 2666
 2667    fn new_file_in_direction(
 2668        workspace: &mut Workspace,
 2669        direction: SplitDirection,
 2670        window: &mut Window,
 2671        cx: &mut Context<Workspace>,
 2672    ) {
 2673        let project = workspace.project().clone();
 2674        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2675
 2676        cx.spawn_in(window, async move |workspace, cx| {
 2677            let buffer = create.await?;
 2678            workspace.update_in(cx, move |workspace, window, cx| {
 2679                workspace.split_item(
 2680                    direction,
 2681                    Box::new(
 2682                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2683                    ),
 2684                    window,
 2685                    cx,
 2686                )
 2687            })?;
 2688            anyhow::Ok(())
 2689        })
 2690        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2691            match e.error_code() {
 2692                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2693                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2694                e.error_tag("required").unwrap_or("the latest version")
 2695            )),
 2696                _ => None,
 2697            }
 2698        });
 2699    }
 2700
 2701    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2702        self.leader_id
 2703    }
 2704
 2705    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2706        &self.buffer
 2707    }
 2708
 2709    pub fn project(&self) -> Option<&Entity<Project>> {
 2710        self.project.as_ref()
 2711    }
 2712
 2713    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2714        self.workspace.as_ref()?.0.upgrade()
 2715    }
 2716
 2717    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2718        self.buffer().read(cx).title(cx)
 2719    }
 2720
 2721    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2722        let git_blame_gutter_max_author_length = self
 2723            .render_git_blame_gutter(cx)
 2724            .then(|| {
 2725                if let Some(blame) = self.blame.as_ref() {
 2726                    let max_author_length =
 2727                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2728                    Some(max_author_length)
 2729                } else {
 2730                    None
 2731                }
 2732            })
 2733            .flatten();
 2734
 2735        EditorSnapshot {
 2736            mode: self.mode.clone(),
 2737            show_gutter: self.show_gutter,
 2738            show_line_numbers: self.show_line_numbers,
 2739            show_git_diff_gutter: self.show_git_diff_gutter,
 2740            show_code_actions: self.show_code_actions,
 2741            show_runnables: self.show_runnables,
 2742            show_breakpoints: self.show_breakpoints,
 2743            git_blame_gutter_max_author_length,
 2744            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2745            placeholder_display_snapshot: self
 2746                .placeholder_display_map
 2747                .as_ref()
 2748                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2749            scroll_anchor: self.scroll_manager.anchor(),
 2750            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2751            is_focused: self.focus_handle.is_focused(window),
 2752            current_line_highlight: self
 2753                .current_line_highlight
 2754                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2755            gutter_hovered: self.gutter_hovered,
 2756        }
 2757    }
 2758
 2759    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2760        self.buffer.read(cx).language_at(point, cx)
 2761    }
 2762
 2763    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2764        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2765    }
 2766
 2767    pub fn active_excerpt(
 2768        &self,
 2769        cx: &App,
 2770    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2771        self.buffer
 2772            .read(cx)
 2773            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2774    }
 2775
 2776    pub fn mode(&self) -> &EditorMode {
 2777        &self.mode
 2778    }
 2779
 2780    pub fn set_mode(&mut self, mode: EditorMode) {
 2781        self.mode = mode;
 2782    }
 2783
 2784    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2785        self.collaboration_hub.as_deref()
 2786    }
 2787
 2788    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2789        self.collaboration_hub = Some(hub);
 2790    }
 2791
 2792    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2793        self.in_project_search = in_project_search;
 2794    }
 2795
 2796    pub fn set_custom_context_menu(
 2797        &mut self,
 2798        f: impl 'static
 2799        + Fn(
 2800            &mut Self,
 2801            DisplayPoint,
 2802            &mut Window,
 2803            &mut Context<Self>,
 2804        ) -> Option<Entity<ui::ContextMenu>>,
 2805    ) {
 2806        self.custom_context_menu = Some(Box::new(f))
 2807    }
 2808
 2809    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2810        self.completion_provider = provider;
 2811    }
 2812
 2813    #[cfg(any(test, feature = "test-support"))]
 2814    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2815        self.completion_provider.clone()
 2816    }
 2817
 2818    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2819        self.semantics_provider.clone()
 2820    }
 2821
 2822    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2823        self.semantics_provider = provider;
 2824    }
 2825
 2826    pub fn set_edit_prediction_provider<T>(
 2827        &mut self,
 2828        provider: Option<Entity<T>>,
 2829        window: &mut Window,
 2830        cx: &mut Context<Self>,
 2831    ) where
 2832        T: EditPredictionProvider,
 2833    {
 2834        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2835            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2836                if this.focus_handle.is_focused(window) {
 2837                    this.update_visible_edit_prediction(window, cx);
 2838                }
 2839            }),
 2840            provider: Arc::new(provider),
 2841        });
 2842        self.update_edit_prediction_settings(cx);
 2843        self.refresh_edit_prediction(false, false, window, cx);
 2844    }
 2845
 2846    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2847        self.placeholder_display_map
 2848            .as_ref()
 2849            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2850    }
 2851
 2852    pub fn set_placeholder_text(
 2853        &mut self,
 2854        placeholder_text: &str,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        let multibuffer = cx
 2859            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2860
 2861        let style = window.text_style();
 2862
 2863        self.placeholder_display_map = Some(cx.new(|cx| {
 2864            DisplayMap::new(
 2865                multibuffer,
 2866                style.font(),
 2867                style.font_size.to_pixels(window.rem_size()),
 2868                None,
 2869                FILE_HEADER_HEIGHT,
 2870                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2871                Default::default(),
 2872                DiagnosticSeverity::Off,
 2873                cx,
 2874            )
 2875        }));
 2876        cx.notify();
 2877    }
 2878
 2879    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2880        self.cursor_shape = cursor_shape;
 2881
 2882        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2883        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2884
 2885        cx.notify();
 2886    }
 2887
 2888    pub fn set_current_line_highlight(
 2889        &mut self,
 2890        current_line_highlight: Option<CurrentLineHighlight>,
 2891    ) {
 2892        self.current_line_highlight = current_line_highlight;
 2893    }
 2894
 2895    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2896        self.collapse_matches = collapse_matches;
 2897    }
 2898
 2899    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2900        let buffers = self.buffer.read(cx).all_buffers();
 2901        let Some(project) = self.project.as_ref() else {
 2902            return;
 2903        };
 2904        project.update(cx, |project, cx| {
 2905            for buffer in buffers {
 2906                self.registered_buffers
 2907                    .entry(buffer.read(cx).remote_id())
 2908                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2909            }
 2910        })
 2911    }
 2912
 2913    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2914        if self.collapse_matches {
 2915            return range.start..range.start;
 2916        }
 2917        range.clone()
 2918    }
 2919
 2920    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2921        if self.display_map.read(cx).clip_at_line_ends != clip {
 2922            self.display_map
 2923                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2924        }
 2925    }
 2926
 2927    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2928        self.input_enabled = input_enabled;
 2929    }
 2930
 2931    pub fn set_edit_predictions_hidden_for_vim_mode(
 2932        &mut self,
 2933        hidden: bool,
 2934        window: &mut Window,
 2935        cx: &mut Context<Self>,
 2936    ) {
 2937        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2938            self.edit_predictions_hidden_for_vim_mode = hidden;
 2939            if hidden {
 2940                self.update_visible_edit_prediction(window, cx);
 2941            } else {
 2942                self.refresh_edit_prediction(true, false, window, cx);
 2943            }
 2944        }
 2945    }
 2946
 2947    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2948        self.menu_edit_predictions_policy = value;
 2949    }
 2950
 2951    pub fn set_autoindent(&mut self, autoindent: bool) {
 2952        if autoindent {
 2953            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2954        } else {
 2955            self.autoindent_mode = None;
 2956        }
 2957    }
 2958
 2959    pub fn read_only(&self, cx: &App) -> bool {
 2960        self.read_only || self.buffer.read(cx).read_only()
 2961    }
 2962
 2963    pub fn set_read_only(&mut self, read_only: bool) {
 2964        self.read_only = read_only;
 2965    }
 2966
 2967    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2968        self.use_autoclose = autoclose;
 2969    }
 2970
 2971    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2972        self.use_auto_surround = auto_surround;
 2973    }
 2974
 2975    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2976        self.auto_replace_emoji_shortcode = auto_replace;
 2977    }
 2978
 2979    pub fn toggle_edit_predictions(
 2980        &mut self,
 2981        _: &ToggleEditPrediction,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984    ) {
 2985        if self.show_edit_predictions_override.is_some() {
 2986            self.set_show_edit_predictions(None, window, cx);
 2987        } else {
 2988            let show_edit_predictions = !self.edit_predictions_enabled();
 2989            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2990        }
 2991    }
 2992
 2993    pub fn set_show_edit_predictions(
 2994        &mut self,
 2995        show_edit_predictions: Option<bool>,
 2996        window: &mut Window,
 2997        cx: &mut Context<Self>,
 2998    ) {
 2999        self.show_edit_predictions_override = show_edit_predictions;
 3000        self.update_edit_prediction_settings(cx);
 3001
 3002        if let Some(false) = show_edit_predictions {
 3003            self.discard_edit_prediction(false, cx);
 3004        } else {
 3005            self.refresh_edit_prediction(false, true, window, cx);
 3006        }
 3007    }
 3008
 3009    fn edit_predictions_disabled_in_scope(
 3010        &self,
 3011        buffer: &Entity<Buffer>,
 3012        buffer_position: language::Anchor,
 3013        cx: &App,
 3014    ) -> bool {
 3015        let snapshot = buffer.read(cx).snapshot();
 3016        let settings = snapshot.settings_at(buffer_position, cx);
 3017
 3018        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3019            return false;
 3020        };
 3021
 3022        scope.override_name().is_some_and(|scope_name| {
 3023            settings
 3024                .edit_predictions_disabled_in
 3025                .iter()
 3026                .any(|s| s == scope_name)
 3027        })
 3028    }
 3029
 3030    pub fn set_use_modal_editing(&mut self, to: bool) {
 3031        self.use_modal_editing = to;
 3032    }
 3033
 3034    pub fn use_modal_editing(&self) -> bool {
 3035        self.use_modal_editing
 3036    }
 3037
 3038    fn selections_did_change(
 3039        &mut self,
 3040        local: bool,
 3041        old_cursor_position: &Anchor,
 3042        effects: SelectionEffects,
 3043        window: &mut Window,
 3044        cx: &mut Context<Self>,
 3045    ) {
 3046        window.invalidate_character_coordinates();
 3047
 3048        // Copy selections to primary selection buffer
 3049        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3050        if local {
 3051            let selections = self.selections.all::<usize>(cx);
 3052            let buffer_handle = self.buffer.read(cx).read(cx);
 3053
 3054            let mut text = String::new();
 3055            for (index, selection) in selections.iter().enumerate() {
 3056                let text_for_selection = buffer_handle
 3057                    .text_for_range(selection.start..selection.end)
 3058                    .collect::<String>();
 3059
 3060                text.push_str(&text_for_selection);
 3061                if index != selections.len() - 1 {
 3062                    text.push('\n');
 3063                }
 3064            }
 3065
 3066            if !text.is_empty() {
 3067                cx.write_to_primary(ClipboardItem::new_string(text));
 3068            }
 3069        }
 3070
 3071        let selection_anchors = self.selections.disjoint_anchors_arc();
 3072
 3073        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3074            self.buffer.update(cx, |buffer, cx| {
 3075                buffer.set_active_selections(
 3076                    &selection_anchors,
 3077                    self.selections.line_mode(),
 3078                    self.cursor_shape,
 3079                    cx,
 3080                )
 3081            });
 3082        }
 3083        let display_map = self
 3084            .display_map
 3085            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3086        let buffer = display_map.buffer_snapshot();
 3087        if self.selections.count() == 1 {
 3088            self.add_selections_state = None;
 3089        }
 3090        self.select_next_state = None;
 3091        self.select_prev_state = None;
 3092        self.select_syntax_node_history.try_clear();
 3093        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3094        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3095        self.take_rename(false, window, cx);
 3096
 3097        let newest_selection = self.selections.newest_anchor();
 3098        let new_cursor_position = newest_selection.head();
 3099        let selection_start = newest_selection.start;
 3100
 3101        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3102            self.push_to_nav_history(
 3103                *old_cursor_position,
 3104                Some(new_cursor_position.to_point(buffer)),
 3105                false,
 3106                effects.nav_history == Some(true),
 3107                cx,
 3108            );
 3109        }
 3110
 3111        if local {
 3112            if let Some(buffer_id) = new_cursor_position.buffer_id
 3113                && !self.registered_buffers.contains_key(&buffer_id)
 3114                && let Some(project) = self.project.as_ref()
 3115            {
 3116                project.update(cx, |project, cx| {
 3117                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3118                        return;
 3119                    };
 3120                    self.registered_buffers.insert(
 3121                        buffer_id,
 3122                        project.register_buffer_with_language_servers(&buffer, cx),
 3123                    );
 3124                })
 3125            }
 3126
 3127            let mut context_menu = self.context_menu.borrow_mut();
 3128            let completion_menu = match context_menu.as_ref() {
 3129                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3130                Some(CodeContextMenu::CodeActions(_)) => {
 3131                    *context_menu = None;
 3132                    None
 3133                }
 3134                None => None,
 3135            };
 3136            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3137            drop(context_menu);
 3138
 3139            if effects.completions
 3140                && let Some(completion_position) = completion_position
 3141            {
 3142                let start_offset = selection_start.to_offset(buffer);
 3143                let position_matches = start_offset == completion_position.to_offset(buffer);
 3144                let continue_showing = if position_matches {
 3145                    if self.snippet_stack.is_empty() {
 3146                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3147                            == Some(CharKind::Word)
 3148                    } else {
 3149                        // Snippet choices can be shown even when the cursor is in whitespace.
 3150                        // Dismissing the menu with actions like backspace is handled by
 3151                        // invalidation regions.
 3152                        true
 3153                    }
 3154                } else {
 3155                    false
 3156                };
 3157
 3158                if continue_showing {
 3159                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3160                } else {
 3161                    self.hide_context_menu(window, cx);
 3162                }
 3163            }
 3164
 3165            hide_hover(self, cx);
 3166
 3167            if old_cursor_position.to_display_point(&display_map).row()
 3168                != new_cursor_position.to_display_point(&display_map).row()
 3169            {
 3170                self.available_code_actions.take();
 3171            }
 3172            self.refresh_code_actions(window, cx);
 3173            self.refresh_document_highlights(cx);
 3174            self.refresh_selected_text_highlights(false, window, cx);
 3175            refresh_matching_bracket_highlights(self, window, cx);
 3176            self.update_visible_edit_prediction(window, cx);
 3177            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3178            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3179            self.inline_blame_popover.take();
 3180            if self.git_blame_inline_enabled {
 3181                self.start_inline_blame_timer(window, cx);
 3182            }
 3183        }
 3184
 3185        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3186        cx.emit(EditorEvent::SelectionsChanged { local });
 3187
 3188        let selections = &self.selections.disjoint_anchors_arc();
 3189        if selections.len() == 1 {
 3190            cx.emit(SearchEvent::ActiveMatchChanged)
 3191        }
 3192        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3193            let inmemory_selections = selections
 3194                .iter()
 3195                .map(|s| {
 3196                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3197                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3198                })
 3199                .collect();
 3200            self.update_restoration_data(cx, |data| {
 3201                data.selections = inmemory_selections;
 3202            });
 3203
 3204            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3205                && let Some(workspace_id) =
 3206                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3207            {
 3208                let snapshot = self.buffer().read(cx).snapshot(cx);
 3209                let selections = selections.clone();
 3210                let background_executor = cx.background_executor().clone();
 3211                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3212                self.serialize_selections = cx.background_spawn(async move {
 3213                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3214                    let db_selections = selections
 3215                        .iter()
 3216                        .map(|selection| {
 3217                            (
 3218                                selection.start.to_offset(&snapshot),
 3219                                selection.end.to_offset(&snapshot),
 3220                            )
 3221                        })
 3222                        .collect();
 3223
 3224                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3225                        .await
 3226                        .with_context(|| {
 3227                            format!(
 3228                                "persisting editor selections for editor {editor_id}, \
 3229                                workspace {workspace_id:?}"
 3230                            )
 3231                        })
 3232                        .log_err();
 3233                });
 3234            }
 3235        }
 3236
 3237        cx.notify();
 3238    }
 3239
 3240    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3241        use text::ToOffset as _;
 3242        use text::ToPoint as _;
 3243
 3244        if self.mode.is_minimap()
 3245            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3246        {
 3247            return;
 3248        }
 3249
 3250        if !self.buffer().read(cx).is_singleton() {
 3251            return;
 3252        }
 3253
 3254        let display_snapshot = self
 3255            .display_map
 3256            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3257        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3258            return;
 3259        };
 3260        let inmemory_folds = display_snapshot
 3261            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3262            .map(|fold| {
 3263                fold.range.start.text_anchor.to_point(&snapshot)
 3264                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3265            })
 3266            .collect();
 3267        self.update_restoration_data(cx, |data| {
 3268            data.folds = inmemory_folds;
 3269        });
 3270
 3271        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3272            return;
 3273        };
 3274        let background_executor = cx.background_executor().clone();
 3275        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3276        let db_folds = display_snapshot
 3277            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3278            .map(|fold| {
 3279                (
 3280                    fold.range.start.text_anchor.to_offset(&snapshot),
 3281                    fold.range.end.text_anchor.to_offset(&snapshot),
 3282                )
 3283            })
 3284            .collect();
 3285        self.serialize_folds = cx.background_spawn(async move {
 3286            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3287            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3288                .await
 3289                .with_context(|| {
 3290                    format!(
 3291                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3292                    )
 3293                })
 3294                .log_err();
 3295        });
 3296    }
 3297
 3298    pub fn sync_selections(
 3299        &mut self,
 3300        other: Entity<Editor>,
 3301        cx: &mut Context<Self>,
 3302    ) -> gpui::Subscription {
 3303        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3304        if !other_selections.is_empty() {
 3305            self.selections.change_with(cx, |selections| {
 3306                selections.select_anchors(other_selections);
 3307            });
 3308        }
 3309
 3310        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3311            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3312                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3313                if other_selections.is_empty() {
 3314                    return;
 3315                }
 3316                this.selections.change_with(cx, |selections| {
 3317                    selections.select_anchors(other_selections);
 3318                });
 3319            }
 3320        });
 3321
 3322        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3323            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3324                let these_selections = this.selections.disjoint_anchors().to_vec();
 3325                if these_selections.is_empty() {
 3326                    return;
 3327                }
 3328                other.update(cx, |other_editor, cx| {
 3329                    other_editor.selections.change_with(cx, |selections| {
 3330                        selections.select_anchors(these_selections);
 3331                    })
 3332                });
 3333            }
 3334        });
 3335
 3336        Subscription::join(other_subscription, this_subscription)
 3337    }
 3338
 3339    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3340    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3341    /// effects of selection change occur at the end of the transaction.
 3342    pub fn change_selections<R>(
 3343        &mut self,
 3344        effects: SelectionEffects,
 3345        window: &mut Window,
 3346        cx: &mut Context<Self>,
 3347        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3348    ) -> R {
 3349        if let Some(state) = &mut self.deferred_selection_effects_state {
 3350            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3351            state.effects.completions = effects.completions;
 3352            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3353            let (changed, result) = self.selections.change_with(cx, change);
 3354            state.changed |= changed;
 3355            return result;
 3356        }
 3357        let mut state = DeferredSelectionEffectsState {
 3358            changed: false,
 3359            effects,
 3360            old_cursor_position: self.selections.newest_anchor().head(),
 3361            history_entry: SelectionHistoryEntry {
 3362                selections: self.selections.disjoint_anchors_arc(),
 3363                select_next_state: self.select_next_state.clone(),
 3364                select_prev_state: self.select_prev_state.clone(),
 3365                add_selections_state: self.add_selections_state.clone(),
 3366            },
 3367        };
 3368        let (changed, result) = self.selections.change_with(cx, change);
 3369        state.changed = state.changed || changed;
 3370        if self.defer_selection_effects {
 3371            self.deferred_selection_effects_state = Some(state);
 3372        } else {
 3373            self.apply_selection_effects(state, window, cx);
 3374        }
 3375        result
 3376    }
 3377
 3378    /// Defers the effects of selection change, so that the effects of multiple calls to
 3379    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3380    /// to selection history and the state of popovers based on selection position aren't
 3381    /// erroneously updated.
 3382    pub fn with_selection_effects_deferred<R>(
 3383        &mut self,
 3384        window: &mut Window,
 3385        cx: &mut Context<Self>,
 3386        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3387    ) -> R {
 3388        let already_deferred = self.defer_selection_effects;
 3389        self.defer_selection_effects = true;
 3390        let result = update(self, window, cx);
 3391        if !already_deferred {
 3392            self.defer_selection_effects = false;
 3393            if let Some(state) = self.deferred_selection_effects_state.take() {
 3394                self.apply_selection_effects(state, window, cx);
 3395            }
 3396        }
 3397        result
 3398    }
 3399
 3400    fn apply_selection_effects(
 3401        &mut self,
 3402        state: DeferredSelectionEffectsState,
 3403        window: &mut Window,
 3404        cx: &mut Context<Self>,
 3405    ) {
 3406        if state.changed {
 3407            self.selection_history.push(state.history_entry);
 3408
 3409            if let Some(autoscroll) = state.effects.scroll {
 3410                self.request_autoscroll(autoscroll, cx);
 3411            }
 3412
 3413            let old_cursor_position = &state.old_cursor_position;
 3414
 3415            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3416
 3417            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3418                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3419            }
 3420        }
 3421    }
 3422
 3423    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3424    where
 3425        I: IntoIterator<Item = (Range<S>, T)>,
 3426        S: ToOffset,
 3427        T: Into<Arc<str>>,
 3428    {
 3429        if self.read_only(cx) {
 3430            return;
 3431        }
 3432
 3433        self.buffer
 3434            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3435    }
 3436
 3437    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3438    where
 3439        I: IntoIterator<Item = (Range<S>, T)>,
 3440        S: ToOffset,
 3441        T: Into<Arc<str>>,
 3442    {
 3443        if self.read_only(cx) {
 3444            return;
 3445        }
 3446
 3447        self.buffer.update(cx, |buffer, cx| {
 3448            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3449        });
 3450    }
 3451
 3452    pub fn edit_with_block_indent<I, S, T>(
 3453        &mut self,
 3454        edits: I,
 3455        original_indent_columns: Vec<Option<u32>>,
 3456        cx: &mut Context<Self>,
 3457    ) where
 3458        I: IntoIterator<Item = (Range<S>, T)>,
 3459        S: ToOffset,
 3460        T: Into<Arc<str>>,
 3461    {
 3462        if self.read_only(cx) {
 3463            return;
 3464        }
 3465
 3466        self.buffer.update(cx, |buffer, cx| {
 3467            buffer.edit(
 3468                edits,
 3469                Some(AutoindentMode::Block {
 3470                    original_indent_columns,
 3471                }),
 3472                cx,
 3473            )
 3474        });
 3475    }
 3476
 3477    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3478        self.hide_context_menu(window, cx);
 3479
 3480        match phase {
 3481            SelectPhase::Begin {
 3482                position,
 3483                add,
 3484                click_count,
 3485            } => self.begin_selection(position, add, click_count, window, cx),
 3486            SelectPhase::BeginColumnar {
 3487                position,
 3488                goal_column,
 3489                reset,
 3490                mode,
 3491            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3492            SelectPhase::Extend {
 3493                position,
 3494                click_count,
 3495            } => self.extend_selection(position, click_count, window, cx),
 3496            SelectPhase::Update {
 3497                position,
 3498                goal_column,
 3499                scroll_delta,
 3500            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3501            SelectPhase::End => self.end_selection(window, cx),
 3502        }
 3503    }
 3504
 3505    fn extend_selection(
 3506        &mut self,
 3507        position: DisplayPoint,
 3508        click_count: usize,
 3509        window: &mut Window,
 3510        cx: &mut Context<Self>,
 3511    ) {
 3512        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3513        let tail = self.selections.newest::<usize>(cx).tail();
 3514        self.begin_selection(position, false, click_count, window, cx);
 3515
 3516        let position = position.to_offset(&display_map, Bias::Left);
 3517        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3518
 3519        let mut pending_selection = self
 3520            .selections
 3521            .pending_anchor()
 3522            .cloned()
 3523            .expect("extend_selection not called with pending selection");
 3524        if position >= tail {
 3525            pending_selection.start = tail_anchor;
 3526        } else {
 3527            pending_selection.end = tail_anchor;
 3528            pending_selection.reversed = true;
 3529        }
 3530
 3531        let mut pending_mode = self.selections.pending_mode().unwrap();
 3532        match &mut pending_mode {
 3533            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3534            _ => {}
 3535        }
 3536
 3537        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3538            SelectionEffects::scroll(Autoscroll::fit())
 3539        } else {
 3540            SelectionEffects::no_scroll()
 3541        };
 3542
 3543        self.change_selections(effects, window, cx, |s| {
 3544            s.set_pending(pending_selection.clone(), pending_mode)
 3545        });
 3546    }
 3547
 3548    fn begin_selection(
 3549        &mut self,
 3550        position: DisplayPoint,
 3551        add: bool,
 3552        click_count: usize,
 3553        window: &mut Window,
 3554        cx: &mut Context<Self>,
 3555    ) {
 3556        if !self.focus_handle.is_focused(window) {
 3557            self.last_focused_descendant = None;
 3558            window.focus(&self.focus_handle);
 3559        }
 3560
 3561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3562        let buffer = display_map.buffer_snapshot();
 3563        let position = display_map.clip_point(position, Bias::Left);
 3564
 3565        let start;
 3566        let end;
 3567        let mode;
 3568        let mut auto_scroll;
 3569        match click_count {
 3570            1 => {
 3571                start = buffer.anchor_before(position.to_point(&display_map));
 3572                end = start;
 3573                mode = SelectMode::Character;
 3574                auto_scroll = true;
 3575            }
 3576            2 => {
 3577                let position = display_map
 3578                    .clip_point(position, Bias::Left)
 3579                    .to_offset(&display_map, Bias::Left);
 3580                let (range, _) = buffer.surrounding_word(position, None);
 3581                start = buffer.anchor_before(range.start);
 3582                end = buffer.anchor_before(range.end);
 3583                mode = SelectMode::Word(start..end);
 3584                auto_scroll = true;
 3585            }
 3586            3 => {
 3587                let position = display_map
 3588                    .clip_point(position, Bias::Left)
 3589                    .to_point(&display_map);
 3590                let line_start = display_map.prev_line_boundary(position).0;
 3591                let next_line_start = buffer.clip_point(
 3592                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3593                    Bias::Left,
 3594                );
 3595                start = buffer.anchor_before(line_start);
 3596                end = buffer.anchor_before(next_line_start);
 3597                mode = SelectMode::Line(start..end);
 3598                auto_scroll = true;
 3599            }
 3600            _ => {
 3601                start = buffer.anchor_before(0);
 3602                end = buffer.anchor_before(buffer.len());
 3603                mode = SelectMode::All;
 3604                auto_scroll = false;
 3605            }
 3606        }
 3607        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3608
 3609        let point_to_delete: Option<usize> = {
 3610            let selected_points: Vec<Selection<Point>> =
 3611                self.selections.disjoint_in_range(start..end, cx);
 3612
 3613            if !add || click_count > 1 {
 3614                None
 3615            } else if !selected_points.is_empty() {
 3616                Some(selected_points[0].id)
 3617            } else {
 3618                let clicked_point_already_selected =
 3619                    self.selections.disjoint_anchors().iter().find(|selection| {
 3620                        selection.start.to_point(buffer) == start.to_point(buffer)
 3621                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3622                    });
 3623
 3624                clicked_point_already_selected.map(|selection| selection.id)
 3625            }
 3626        };
 3627
 3628        let selections_count = self.selections.count();
 3629        let effects = if auto_scroll {
 3630            SelectionEffects::default()
 3631        } else {
 3632            SelectionEffects::no_scroll()
 3633        };
 3634
 3635        self.change_selections(effects, window, cx, |s| {
 3636            if let Some(point_to_delete) = point_to_delete {
 3637                s.delete(point_to_delete);
 3638
 3639                if selections_count == 1 {
 3640                    s.set_pending_anchor_range(start..end, mode);
 3641                }
 3642            } else {
 3643                if !add {
 3644                    s.clear_disjoint();
 3645                }
 3646
 3647                s.set_pending_anchor_range(start..end, mode);
 3648            }
 3649        });
 3650    }
 3651
 3652    fn begin_columnar_selection(
 3653        &mut self,
 3654        position: DisplayPoint,
 3655        goal_column: u32,
 3656        reset: bool,
 3657        mode: ColumnarMode,
 3658        window: &mut Window,
 3659        cx: &mut Context<Self>,
 3660    ) {
 3661        if !self.focus_handle.is_focused(window) {
 3662            self.last_focused_descendant = None;
 3663            window.focus(&self.focus_handle);
 3664        }
 3665
 3666        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3667
 3668        if reset {
 3669            let pointer_position = display_map
 3670                .buffer_snapshot()
 3671                .anchor_before(position.to_point(&display_map));
 3672
 3673            self.change_selections(
 3674                SelectionEffects::scroll(Autoscroll::newest()),
 3675                window,
 3676                cx,
 3677                |s| {
 3678                    s.clear_disjoint();
 3679                    s.set_pending_anchor_range(
 3680                        pointer_position..pointer_position,
 3681                        SelectMode::Character,
 3682                    );
 3683                },
 3684            );
 3685        };
 3686
 3687        let tail = self.selections.newest::<Point>(cx).tail();
 3688        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3689        self.columnar_selection_state = match mode {
 3690            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3691                selection_tail: selection_anchor,
 3692                display_point: if reset {
 3693                    if position.column() != goal_column {
 3694                        Some(DisplayPoint::new(position.row(), goal_column))
 3695                    } else {
 3696                        None
 3697                    }
 3698                } else {
 3699                    None
 3700                },
 3701            }),
 3702            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3703                selection_tail: selection_anchor,
 3704            }),
 3705        };
 3706
 3707        if !reset {
 3708            self.select_columns(position, goal_column, &display_map, window, cx);
 3709        }
 3710    }
 3711
 3712    fn update_selection(
 3713        &mut self,
 3714        position: DisplayPoint,
 3715        goal_column: u32,
 3716        scroll_delta: gpui::Point<f32>,
 3717        window: &mut Window,
 3718        cx: &mut Context<Self>,
 3719    ) {
 3720        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3721
 3722        if self.columnar_selection_state.is_some() {
 3723            self.select_columns(position, goal_column, &display_map, window, cx);
 3724        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3725            let buffer = display_map.buffer_snapshot();
 3726            let head;
 3727            let tail;
 3728            let mode = self.selections.pending_mode().unwrap();
 3729            match &mode {
 3730                SelectMode::Character => {
 3731                    head = position.to_point(&display_map);
 3732                    tail = pending.tail().to_point(buffer);
 3733                }
 3734                SelectMode::Word(original_range) => {
 3735                    let offset = display_map
 3736                        .clip_point(position, Bias::Left)
 3737                        .to_offset(&display_map, Bias::Left);
 3738                    let original_range = original_range.to_offset(buffer);
 3739
 3740                    let head_offset = if buffer.is_inside_word(offset, None)
 3741                        || original_range.contains(&offset)
 3742                    {
 3743                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3744                        if word_range.start < original_range.start {
 3745                            word_range.start
 3746                        } else {
 3747                            word_range.end
 3748                        }
 3749                    } else {
 3750                        offset
 3751                    };
 3752
 3753                    head = head_offset.to_point(buffer);
 3754                    if head_offset <= original_range.start {
 3755                        tail = original_range.end.to_point(buffer);
 3756                    } else {
 3757                        tail = original_range.start.to_point(buffer);
 3758                    }
 3759                }
 3760                SelectMode::Line(original_range) => {
 3761                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3762
 3763                    let position = display_map
 3764                        .clip_point(position, Bias::Left)
 3765                        .to_point(&display_map);
 3766                    let line_start = display_map.prev_line_boundary(position).0;
 3767                    let next_line_start = buffer.clip_point(
 3768                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3769                        Bias::Left,
 3770                    );
 3771
 3772                    if line_start < original_range.start {
 3773                        head = line_start
 3774                    } else {
 3775                        head = next_line_start
 3776                    }
 3777
 3778                    if head <= original_range.start {
 3779                        tail = original_range.end;
 3780                    } else {
 3781                        tail = original_range.start;
 3782                    }
 3783                }
 3784                SelectMode::All => {
 3785                    return;
 3786                }
 3787            };
 3788
 3789            if head < tail {
 3790                pending.start = buffer.anchor_before(head);
 3791                pending.end = buffer.anchor_before(tail);
 3792                pending.reversed = true;
 3793            } else {
 3794                pending.start = buffer.anchor_before(tail);
 3795                pending.end = buffer.anchor_before(head);
 3796                pending.reversed = false;
 3797            }
 3798
 3799            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3800                s.set_pending(pending.clone(), mode);
 3801            });
 3802        } else {
 3803            log::error!("update_selection dispatched with no pending selection");
 3804            return;
 3805        }
 3806
 3807        self.apply_scroll_delta(scroll_delta, window, cx);
 3808        cx.notify();
 3809    }
 3810
 3811    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3812        self.columnar_selection_state.take();
 3813        if self.selections.pending_anchor().is_some() {
 3814            let selections = self.selections.all::<usize>(cx);
 3815            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3816                s.select(selections);
 3817                s.clear_pending();
 3818            });
 3819        }
 3820    }
 3821
 3822    fn select_columns(
 3823        &mut self,
 3824        head: DisplayPoint,
 3825        goal_column: u32,
 3826        display_map: &DisplaySnapshot,
 3827        window: &mut Window,
 3828        cx: &mut Context<Self>,
 3829    ) {
 3830        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3831            return;
 3832        };
 3833
 3834        let tail = match columnar_state {
 3835            ColumnarSelectionState::FromMouse {
 3836                selection_tail,
 3837                display_point,
 3838            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3839            ColumnarSelectionState::FromSelection { selection_tail } => {
 3840                selection_tail.to_display_point(display_map)
 3841            }
 3842        };
 3843
 3844        let start_row = cmp::min(tail.row(), head.row());
 3845        let end_row = cmp::max(tail.row(), head.row());
 3846        let start_column = cmp::min(tail.column(), goal_column);
 3847        let end_column = cmp::max(tail.column(), goal_column);
 3848        let reversed = start_column < tail.column();
 3849
 3850        let selection_ranges = (start_row.0..=end_row.0)
 3851            .map(DisplayRow)
 3852            .filter_map(|row| {
 3853                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3854                    || start_column <= display_map.line_len(row))
 3855                    && !display_map.is_block_line(row)
 3856                {
 3857                    let start = display_map
 3858                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3859                        .to_point(display_map);
 3860                    let end = display_map
 3861                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3862                        .to_point(display_map);
 3863                    if reversed {
 3864                        Some(end..start)
 3865                    } else {
 3866                        Some(start..end)
 3867                    }
 3868                } else {
 3869                    None
 3870                }
 3871            })
 3872            .collect::<Vec<_>>();
 3873
 3874        let ranges = match columnar_state {
 3875            ColumnarSelectionState::FromMouse { .. } => {
 3876                let mut non_empty_ranges = selection_ranges
 3877                    .iter()
 3878                    .filter(|selection_range| selection_range.start != selection_range.end)
 3879                    .peekable();
 3880                if non_empty_ranges.peek().is_some() {
 3881                    non_empty_ranges.cloned().collect()
 3882                } else {
 3883                    selection_ranges
 3884                }
 3885            }
 3886            _ => selection_ranges,
 3887        };
 3888
 3889        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3890            s.select_ranges(ranges);
 3891        });
 3892        cx.notify();
 3893    }
 3894
 3895    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3896        self.selections
 3897            .all_adjusted(cx)
 3898            .iter()
 3899            .any(|selection| !selection.is_empty())
 3900    }
 3901
 3902    pub fn has_pending_nonempty_selection(&self) -> bool {
 3903        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3904            Some(Selection { start, end, .. }) => start != end,
 3905            None => false,
 3906        };
 3907
 3908        pending_nonempty_selection
 3909            || (self.columnar_selection_state.is_some()
 3910                && self.selections.disjoint_anchors().len() > 1)
 3911    }
 3912
 3913    pub fn has_pending_selection(&self) -> bool {
 3914        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3915    }
 3916
 3917    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3918        self.selection_mark_mode = false;
 3919        self.selection_drag_state = SelectionDragState::None;
 3920
 3921        if self.clear_expanded_diff_hunks(cx) {
 3922            cx.notify();
 3923            return;
 3924        }
 3925        if self.dismiss_menus_and_popups(true, window, cx) {
 3926            return;
 3927        }
 3928
 3929        if self.mode.is_full()
 3930            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3931        {
 3932            return;
 3933        }
 3934
 3935        cx.propagate();
 3936    }
 3937
 3938    pub fn dismiss_menus_and_popups(
 3939        &mut self,
 3940        is_user_requested: bool,
 3941        window: &mut Window,
 3942        cx: &mut Context<Self>,
 3943    ) -> bool {
 3944        if self.take_rename(false, window, cx).is_some() {
 3945            return true;
 3946        }
 3947
 3948        if hide_hover(self, cx) {
 3949            return true;
 3950        }
 3951
 3952        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3953            return true;
 3954        }
 3955
 3956        if self.hide_context_menu(window, cx).is_some() {
 3957            return true;
 3958        }
 3959
 3960        if self.mouse_context_menu.take().is_some() {
 3961            return true;
 3962        }
 3963
 3964        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3965            return true;
 3966        }
 3967
 3968        if self.snippet_stack.pop().is_some() {
 3969            return true;
 3970        }
 3971
 3972        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3973            self.dismiss_diagnostics(cx);
 3974            return true;
 3975        }
 3976
 3977        false
 3978    }
 3979
 3980    fn linked_editing_ranges_for(
 3981        &self,
 3982        selection: Range<text::Anchor>,
 3983        cx: &App,
 3984    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3985        if self.linked_edit_ranges.is_empty() {
 3986            return None;
 3987        }
 3988        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3989            selection.end.buffer_id.and_then(|end_buffer_id| {
 3990                if selection.start.buffer_id != Some(end_buffer_id) {
 3991                    return None;
 3992                }
 3993                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3994                let snapshot = buffer.read(cx).snapshot();
 3995                self.linked_edit_ranges
 3996                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3997                    .map(|ranges| (ranges, snapshot, buffer))
 3998            })?;
 3999        use text::ToOffset as TO;
 4000        // find offset from the start of current range to current cursor position
 4001        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4002
 4003        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4004        let start_difference = start_offset - start_byte_offset;
 4005        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4006        let end_difference = end_offset - start_byte_offset;
 4007        // Current range has associated linked ranges.
 4008        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4009        for range in linked_ranges.iter() {
 4010            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4011            let end_offset = start_offset + end_difference;
 4012            let start_offset = start_offset + start_difference;
 4013            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4014                continue;
 4015            }
 4016            if self.selections.disjoint_anchor_ranges().any(|s| {
 4017                if s.start.buffer_id != selection.start.buffer_id
 4018                    || s.end.buffer_id != selection.end.buffer_id
 4019                {
 4020                    return false;
 4021                }
 4022                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4023                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4024            }) {
 4025                continue;
 4026            }
 4027            let start = buffer_snapshot.anchor_after(start_offset);
 4028            let end = buffer_snapshot.anchor_after(end_offset);
 4029            linked_edits
 4030                .entry(buffer.clone())
 4031                .or_default()
 4032                .push(start..end);
 4033        }
 4034        Some(linked_edits)
 4035    }
 4036
 4037    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4038        let text: Arc<str> = text.into();
 4039
 4040        if self.read_only(cx) {
 4041            return;
 4042        }
 4043
 4044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4045
 4046        let selections = self.selections.all_adjusted(cx);
 4047        let mut bracket_inserted = false;
 4048        let mut edits = Vec::new();
 4049        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4050        let mut new_selections = Vec::with_capacity(selections.len());
 4051        let mut new_autoclose_regions = Vec::new();
 4052        let snapshot = self.buffer.read(cx).read(cx);
 4053        let mut clear_linked_edit_ranges = false;
 4054
 4055        for (selection, autoclose_region) in
 4056            self.selections_with_autoclose_regions(selections, &snapshot)
 4057        {
 4058            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4059                // Determine if the inserted text matches the opening or closing
 4060                // bracket of any of this language's bracket pairs.
 4061                let mut bracket_pair = None;
 4062                let mut is_bracket_pair_start = false;
 4063                let mut is_bracket_pair_end = false;
 4064                if !text.is_empty() {
 4065                    let mut bracket_pair_matching_end = None;
 4066                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4067                    //  and they are removing the character that triggered IME popup.
 4068                    for (pair, enabled) in scope.brackets() {
 4069                        if !pair.close && !pair.surround {
 4070                            continue;
 4071                        }
 4072
 4073                        if enabled && pair.start.ends_with(text.as_ref()) {
 4074                            let prefix_len = pair.start.len() - text.len();
 4075                            let preceding_text_matches_prefix = prefix_len == 0
 4076                                || (selection.start.column >= (prefix_len as u32)
 4077                                    && snapshot.contains_str_at(
 4078                                        Point::new(
 4079                                            selection.start.row,
 4080                                            selection.start.column - (prefix_len as u32),
 4081                                        ),
 4082                                        &pair.start[..prefix_len],
 4083                                    ));
 4084                            if preceding_text_matches_prefix {
 4085                                bracket_pair = Some(pair.clone());
 4086                                is_bracket_pair_start = true;
 4087                                break;
 4088                            }
 4089                        }
 4090                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4091                        {
 4092                            // take first bracket pair matching end, but don't break in case a later bracket
 4093                            // pair matches start
 4094                            bracket_pair_matching_end = Some(pair.clone());
 4095                        }
 4096                    }
 4097                    if let Some(end) = bracket_pair_matching_end
 4098                        && bracket_pair.is_none()
 4099                    {
 4100                        bracket_pair = Some(end);
 4101                        is_bracket_pair_end = true;
 4102                    }
 4103                }
 4104
 4105                if let Some(bracket_pair) = bracket_pair {
 4106                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4107                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4108                    let auto_surround =
 4109                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4110                    if selection.is_empty() {
 4111                        if is_bracket_pair_start {
 4112                            // If the inserted text is a suffix of an opening bracket and the
 4113                            // selection is preceded by the rest of the opening bracket, then
 4114                            // insert the closing bracket.
 4115                            let following_text_allows_autoclose = snapshot
 4116                                .chars_at(selection.start)
 4117                                .next()
 4118                                .is_none_or(|c| scope.should_autoclose_before(c));
 4119
 4120                            let preceding_text_allows_autoclose = selection.start.column == 0
 4121                                || snapshot
 4122                                    .reversed_chars_at(selection.start)
 4123                                    .next()
 4124                                    .is_none_or(|c| {
 4125                                        bracket_pair.start != bracket_pair.end
 4126                                            || !snapshot
 4127                                                .char_classifier_at(selection.start)
 4128                                                .is_word(c)
 4129                                    });
 4130
 4131                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4132                                && bracket_pair.start.len() == 1
 4133                            {
 4134                                let target = bracket_pair.start.chars().next().unwrap();
 4135                                let current_line_count = snapshot
 4136                                    .reversed_chars_at(selection.start)
 4137                                    .take_while(|&c| c != '\n')
 4138                                    .filter(|&c| c == target)
 4139                                    .count();
 4140                                current_line_count % 2 == 1
 4141                            } else {
 4142                                false
 4143                            };
 4144
 4145                            if autoclose
 4146                                && bracket_pair.close
 4147                                && following_text_allows_autoclose
 4148                                && preceding_text_allows_autoclose
 4149                                && !is_closing_quote
 4150                            {
 4151                                let anchor = snapshot.anchor_before(selection.end);
 4152                                new_selections.push((selection.map(|_| anchor), text.len()));
 4153                                new_autoclose_regions.push((
 4154                                    anchor,
 4155                                    text.len(),
 4156                                    selection.id,
 4157                                    bracket_pair.clone(),
 4158                                ));
 4159                                edits.push((
 4160                                    selection.range(),
 4161                                    format!("{}{}", text, bracket_pair.end).into(),
 4162                                ));
 4163                                bracket_inserted = true;
 4164                                continue;
 4165                            }
 4166                        }
 4167
 4168                        if let Some(region) = autoclose_region {
 4169                            // If the selection is followed by an auto-inserted closing bracket,
 4170                            // then don't insert that closing bracket again; just move the selection
 4171                            // past the closing bracket.
 4172                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4173                                && text.as_ref() == region.pair.end.as_str()
 4174                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4175                            if should_skip {
 4176                                let anchor = snapshot.anchor_after(selection.end);
 4177                                new_selections
 4178                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4179                                continue;
 4180                            }
 4181                        }
 4182
 4183                        let always_treat_brackets_as_autoclosed = snapshot
 4184                            .language_settings_at(selection.start, cx)
 4185                            .always_treat_brackets_as_autoclosed;
 4186                        if always_treat_brackets_as_autoclosed
 4187                            && is_bracket_pair_end
 4188                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4189                        {
 4190                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4191                            // and the inserted text is a closing bracket and the selection is followed
 4192                            // by the closing bracket then move the selection past the closing bracket.
 4193                            let anchor = snapshot.anchor_after(selection.end);
 4194                            new_selections.push((selection.map(|_| anchor), text.len()));
 4195                            continue;
 4196                        }
 4197                    }
 4198                    // If an opening bracket is 1 character long and is typed while
 4199                    // text is selected, then surround that text with the bracket pair.
 4200                    else if auto_surround
 4201                        && bracket_pair.surround
 4202                        && is_bracket_pair_start
 4203                        && bracket_pair.start.chars().count() == 1
 4204                    {
 4205                        edits.push((selection.start..selection.start, text.clone()));
 4206                        edits.push((
 4207                            selection.end..selection.end,
 4208                            bracket_pair.end.as_str().into(),
 4209                        ));
 4210                        bracket_inserted = true;
 4211                        new_selections.push((
 4212                            Selection {
 4213                                id: selection.id,
 4214                                start: snapshot.anchor_after(selection.start),
 4215                                end: snapshot.anchor_before(selection.end),
 4216                                reversed: selection.reversed,
 4217                                goal: selection.goal,
 4218                            },
 4219                            0,
 4220                        ));
 4221                        continue;
 4222                    }
 4223                }
 4224            }
 4225
 4226            if self.auto_replace_emoji_shortcode
 4227                && selection.is_empty()
 4228                && text.as_ref().ends_with(':')
 4229                && let Some(possible_emoji_short_code) =
 4230                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4231                && !possible_emoji_short_code.is_empty()
 4232                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4233            {
 4234                let emoji_shortcode_start = Point::new(
 4235                    selection.start.row,
 4236                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4237                );
 4238
 4239                // Remove shortcode from buffer
 4240                edits.push((
 4241                    emoji_shortcode_start..selection.start,
 4242                    "".to_string().into(),
 4243                ));
 4244                new_selections.push((
 4245                    Selection {
 4246                        id: selection.id,
 4247                        start: snapshot.anchor_after(emoji_shortcode_start),
 4248                        end: snapshot.anchor_before(selection.start),
 4249                        reversed: selection.reversed,
 4250                        goal: selection.goal,
 4251                    },
 4252                    0,
 4253                ));
 4254
 4255                // Insert emoji
 4256                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4257                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4258                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4259
 4260                continue;
 4261            }
 4262
 4263            // If not handling any auto-close operation, then just replace the selected
 4264            // text with the given input and move the selection to the end of the
 4265            // newly inserted text.
 4266            let anchor = snapshot.anchor_after(selection.end);
 4267            if !self.linked_edit_ranges.is_empty() {
 4268                let start_anchor = snapshot.anchor_before(selection.start);
 4269
 4270                let is_word_char = text.chars().next().is_none_or(|char| {
 4271                    let classifier = snapshot
 4272                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4273                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4274                    classifier.is_word(char)
 4275                });
 4276
 4277                if is_word_char {
 4278                    if let Some(ranges) = self
 4279                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4280                    {
 4281                        for (buffer, edits) in ranges {
 4282                            linked_edits
 4283                                .entry(buffer.clone())
 4284                                .or_default()
 4285                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4286                        }
 4287                    }
 4288                } else {
 4289                    clear_linked_edit_ranges = true;
 4290                }
 4291            }
 4292
 4293            new_selections.push((selection.map(|_| anchor), 0));
 4294            edits.push((selection.start..selection.end, text.clone()));
 4295        }
 4296
 4297        drop(snapshot);
 4298
 4299        self.transact(window, cx, |this, window, cx| {
 4300            if clear_linked_edit_ranges {
 4301                this.linked_edit_ranges.clear();
 4302            }
 4303            let initial_buffer_versions =
 4304                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4305
 4306            this.buffer.update(cx, |buffer, cx| {
 4307                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4308            });
 4309            for (buffer, edits) in linked_edits {
 4310                buffer.update(cx, |buffer, cx| {
 4311                    let snapshot = buffer.snapshot();
 4312                    let edits = edits
 4313                        .into_iter()
 4314                        .map(|(range, text)| {
 4315                            use text::ToPoint as TP;
 4316                            let end_point = TP::to_point(&range.end, &snapshot);
 4317                            let start_point = TP::to_point(&range.start, &snapshot);
 4318                            (start_point..end_point, text)
 4319                        })
 4320                        .sorted_by_key(|(range, _)| range.start);
 4321                    buffer.edit(edits, None, cx);
 4322                })
 4323            }
 4324            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4325            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4326            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4327            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4328                .zip(new_selection_deltas)
 4329                .map(|(selection, delta)| Selection {
 4330                    id: selection.id,
 4331                    start: selection.start + delta,
 4332                    end: selection.end + delta,
 4333                    reversed: selection.reversed,
 4334                    goal: SelectionGoal::None,
 4335                })
 4336                .collect::<Vec<_>>();
 4337
 4338            let mut i = 0;
 4339            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4340                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4341                let start = map.buffer_snapshot().anchor_before(position);
 4342                let end = map.buffer_snapshot().anchor_after(position);
 4343                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4344                    match existing_state
 4345                        .range
 4346                        .start
 4347                        .cmp(&start, map.buffer_snapshot())
 4348                    {
 4349                        Ordering::Less => i += 1,
 4350                        Ordering::Greater => break,
 4351                        Ordering::Equal => {
 4352                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4353                                Ordering::Less => i += 1,
 4354                                Ordering::Equal => break,
 4355                                Ordering::Greater => break,
 4356                            }
 4357                        }
 4358                    }
 4359                }
 4360                this.autoclose_regions.insert(
 4361                    i,
 4362                    AutocloseRegion {
 4363                        selection_id,
 4364                        range: start..end,
 4365                        pair,
 4366                    },
 4367                );
 4368            }
 4369
 4370            let had_active_edit_prediction = this.has_active_edit_prediction();
 4371            this.change_selections(
 4372                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4373                window,
 4374                cx,
 4375                |s| s.select(new_selections),
 4376            );
 4377
 4378            if !bracket_inserted
 4379                && let Some(on_type_format_task) =
 4380                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4381            {
 4382                on_type_format_task.detach_and_log_err(cx);
 4383            }
 4384
 4385            let editor_settings = EditorSettings::get_global(cx);
 4386            if bracket_inserted
 4387                && (editor_settings.auto_signature_help
 4388                    || editor_settings.show_signature_help_after_edits)
 4389            {
 4390                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4391            }
 4392
 4393            let trigger_in_words =
 4394                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4395            if this.hard_wrap.is_some() {
 4396                let latest: Range<Point> = this.selections.newest(cx).range();
 4397                if latest.is_empty()
 4398                    && this
 4399                        .buffer()
 4400                        .read(cx)
 4401                        .snapshot(cx)
 4402                        .line_len(MultiBufferRow(latest.start.row))
 4403                        == latest.start.column
 4404                {
 4405                    this.rewrap_impl(
 4406                        RewrapOptions {
 4407                            override_language_settings: true,
 4408                            preserve_existing_whitespace: true,
 4409                        },
 4410                        cx,
 4411                    )
 4412                }
 4413            }
 4414            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4415            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4416            this.refresh_edit_prediction(true, false, window, cx);
 4417            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4418        });
 4419    }
 4420
 4421    fn find_possible_emoji_shortcode_at_position(
 4422        snapshot: &MultiBufferSnapshot,
 4423        position: Point,
 4424    ) -> Option<String> {
 4425        let mut chars = Vec::new();
 4426        let mut found_colon = false;
 4427        for char in snapshot.reversed_chars_at(position).take(100) {
 4428            // Found a possible emoji shortcode in the middle of the buffer
 4429            if found_colon {
 4430                if char.is_whitespace() {
 4431                    chars.reverse();
 4432                    return Some(chars.iter().collect());
 4433                }
 4434                // If the previous character is not a whitespace, we are in the middle of a word
 4435                // and we only want to complete the shortcode if the word is made up of other emojis
 4436                let mut containing_word = String::new();
 4437                for ch in snapshot
 4438                    .reversed_chars_at(position)
 4439                    .skip(chars.len() + 1)
 4440                    .take(100)
 4441                {
 4442                    if ch.is_whitespace() {
 4443                        break;
 4444                    }
 4445                    containing_word.push(ch);
 4446                }
 4447                let containing_word = containing_word.chars().rev().collect::<String>();
 4448                if util::word_consists_of_emojis(containing_word.as_str()) {
 4449                    chars.reverse();
 4450                    return Some(chars.iter().collect());
 4451                }
 4452            }
 4453
 4454            if char.is_whitespace() || !char.is_ascii() {
 4455                return None;
 4456            }
 4457            if char == ':' {
 4458                found_colon = true;
 4459            } else {
 4460                chars.push(char);
 4461            }
 4462        }
 4463        // Found a possible emoji shortcode at the beginning of the buffer
 4464        chars.reverse();
 4465        Some(chars.iter().collect())
 4466    }
 4467
 4468    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4470        self.transact(window, cx, |this, window, cx| {
 4471            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4472                let selections = this.selections.all::<usize>(cx);
 4473                let multi_buffer = this.buffer.read(cx);
 4474                let buffer = multi_buffer.snapshot(cx);
 4475                selections
 4476                    .iter()
 4477                    .map(|selection| {
 4478                        let start_point = selection.start.to_point(&buffer);
 4479                        let mut existing_indent =
 4480                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4481                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4482                        let start = selection.start;
 4483                        let end = selection.end;
 4484                        let selection_is_empty = start == end;
 4485                        let language_scope = buffer.language_scope_at(start);
 4486                        let (
 4487                            comment_delimiter,
 4488                            doc_delimiter,
 4489                            insert_extra_newline,
 4490                            indent_on_newline,
 4491                            indent_on_extra_newline,
 4492                        ) = if let Some(language) = &language_scope {
 4493                            let mut insert_extra_newline =
 4494                                insert_extra_newline_brackets(&buffer, start..end, language)
 4495                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4496
 4497                            // Comment extension on newline is allowed only for cursor selections
 4498                            let comment_delimiter = maybe!({
 4499                                if !selection_is_empty {
 4500                                    return None;
 4501                                }
 4502
 4503                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4504                                    return None;
 4505                                }
 4506
 4507                                let delimiters = language.line_comment_prefixes();
 4508                                let max_len_of_delimiter =
 4509                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4510                                let (snapshot, range) =
 4511                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4512
 4513                                let num_of_whitespaces = snapshot
 4514                                    .chars_for_range(range.clone())
 4515                                    .take_while(|c| c.is_whitespace())
 4516                                    .count();
 4517                                let comment_candidate = snapshot
 4518                                    .chars_for_range(range.clone())
 4519                                    .skip(num_of_whitespaces)
 4520                                    .take(max_len_of_delimiter)
 4521                                    .collect::<String>();
 4522                                let (delimiter, trimmed_len) = delimiters
 4523                                    .iter()
 4524                                    .filter_map(|delimiter| {
 4525                                        let prefix = delimiter.trim_end();
 4526                                        if comment_candidate.starts_with(prefix) {
 4527                                            Some((delimiter, prefix.len()))
 4528                                        } else {
 4529                                            None
 4530                                        }
 4531                                    })
 4532                                    .max_by_key(|(_, len)| *len)?;
 4533
 4534                                if let Some(BlockCommentConfig {
 4535                                    start: block_start, ..
 4536                                }) = language.block_comment()
 4537                                {
 4538                                    let block_start_trimmed = block_start.trim_end();
 4539                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4540                                        let line_content = snapshot
 4541                                            .chars_for_range(range)
 4542                                            .skip(num_of_whitespaces)
 4543                                            .take(block_start_trimmed.len())
 4544                                            .collect::<String>();
 4545
 4546                                        if line_content.starts_with(block_start_trimmed) {
 4547                                            return None;
 4548                                        }
 4549                                    }
 4550                                }
 4551
 4552                                let cursor_is_placed_after_comment_marker =
 4553                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4554                                if cursor_is_placed_after_comment_marker {
 4555                                    Some(delimiter.clone())
 4556                                } else {
 4557                                    None
 4558                                }
 4559                            });
 4560
 4561                            let mut indent_on_newline = IndentSize::spaces(0);
 4562                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4563
 4564                            let doc_delimiter = maybe!({
 4565                                if !selection_is_empty {
 4566                                    return None;
 4567                                }
 4568
 4569                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4570                                    return None;
 4571                                }
 4572
 4573                                let BlockCommentConfig {
 4574                                    start: start_tag,
 4575                                    end: end_tag,
 4576                                    prefix: delimiter,
 4577                                    tab_size: len,
 4578                                } = language.documentation_comment()?;
 4579                                let is_within_block_comment = buffer
 4580                                    .language_scope_at(start_point)
 4581                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4582                                if !is_within_block_comment {
 4583                                    return None;
 4584                                }
 4585
 4586                                let (snapshot, range) =
 4587                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4588
 4589                                let num_of_whitespaces = snapshot
 4590                                    .chars_for_range(range.clone())
 4591                                    .take_while(|c| c.is_whitespace())
 4592                                    .count();
 4593
 4594                                // 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.
 4595                                let column = start_point.column;
 4596                                let cursor_is_after_start_tag = {
 4597                                    let start_tag_len = start_tag.len();
 4598                                    let start_tag_line = snapshot
 4599                                        .chars_for_range(range.clone())
 4600                                        .skip(num_of_whitespaces)
 4601                                        .take(start_tag_len)
 4602                                        .collect::<String>();
 4603                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4604                                        num_of_whitespaces + start_tag_len <= column as usize
 4605                                    } else {
 4606                                        false
 4607                                    }
 4608                                };
 4609
 4610                                let cursor_is_after_delimiter = {
 4611                                    let delimiter_trim = delimiter.trim_end();
 4612                                    let delimiter_line = snapshot
 4613                                        .chars_for_range(range.clone())
 4614                                        .skip(num_of_whitespaces)
 4615                                        .take(delimiter_trim.len())
 4616                                        .collect::<String>();
 4617                                    if delimiter_line.starts_with(delimiter_trim) {
 4618                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4619                                    } else {
 4620                                        false
 4621                                    }
 4622                                };
 4623
 4624                                let cursor_is_before_end_tag_if_exists = {
 4625                                    let mut char_position = 0u32;
 4626                                    let mut end_tag_offset = None;
 4627
 4628                                    'outer: for chunk in snapshot.text_for_range(range) {
 4629                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4630                                            let chars_before_match =
 4631                                                chunk[..byte_pos].chars().count() as u32;
 4632                                            end_tag_offset =
 4633                                                Some(char_position + chars_before_match);
 4634                                            break 'outer;
 4635                                        }
 4636                                        char_position += chunk.chars().count() as u32;
 4637                                    }
 4638
 4639                                    if let Some(end_tag_offset) = end_tag_offset {
 4640                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4641                                        if cursor_is_after_start_tag {
 4642                                            if cursor_is_before_end_tag {
 4643                                                insert_extra_newline = true;
 4644                                            }
 4645                                            let cursor_is_at_start_of_end_tag =
 4646                                                column == end_tag_offset;
 4647                                            if cursor_is_at_start_of_end_tag {
 4648                                                indent_on_extra_newline.len = *len;
 4649                                            }
 4650                                        }
 4651                                        cursor_is_before_end_tag
 4652                                    } else {
 4653                                        true
 4654                                    }
 4655                                };
 4656
 4657                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4658                                    && cursor_is_before_end_tag_if_exists
 4659                                {
 4660                                    if cursor_is_after_start_tag {
 4661                                        indent_on_newline.len = *len;
 4662                                    }
 4663                                    Some(delimiter.clone())
 4664                                } else {
 4665                                    None
 4666                                }
 4667                            });
 4668
 4669                            (
 4670                                comment_delimiter,
 4671                                doc_delimiter,
 4672                                insert_extra_newline,
 4673                                indent_on_newline,
 4674                                indent_on_extra_newline,
 4675                            )
 4676                        } else {
 4677                            (
 4678                                None,
 4679                                None,
 4680                                false,
 4681                                IndentSize::default(),
 4682                                IndentSize::default(),
 4683                            )
 4684                        };
 4685
 4686                        let prevent_auto_indent = doc_delimiter.is_some();
 4687                        let delimiter = comment_delimiter.or(doc_delimiter);
 4688
 4689                        let capacity_for_delimiter =
 4690                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4691                        let mut new_text = String::with_capacity(
 4692                            1 + capacity_for_delimiter
 4693                                + existing_indent.len as usize
 4694                                + indent_on_newline.len as usize
 4695                                + indent_on_extra_newline.len as usize,
 4696                        );
 4697                        new_text.push('\n');
 4698                        new_text.extend(existing_indent.chars());
 4699                        new_text.extend(indent_on_newline.chars());
 4700
 4701                        if let Some(delimiter) = &delimiter {
 4702                            new_text.push_str(delimiter);
 4703                        }
 4704
 4705                        if insert_extra_newline {
 4706                            new_text.push('\n');
 4707                            new_text.extend(existing_indent.chars());
 4708                            new_text.extend(indent_on_extra_newline.chars());
 4709                        }
 4710
 4711                        let anchor = buffer.anchor_after(end);
 4712                        let new_selection = selection.map(|_| anchor);
 4713                        (
 4714                            ((start..end, new_text), prevent_auto_indent),
 4715                            (insert_extra_newline, new_selection),
 4716                        )
 4717                    })
 4718                    .unzip()
 4719            };
 4720
 4721            let mut auto_indent_edits = Vec::new();
 4722            let mut edits = Vec::new();
 4723            for (edit, prevent_auto_indent) in edits_with_flags {
 4724                if prevent_auto_indent {
 4725                    edits.push(edit);
 4726                } else {
 4727                    auto_indent_edits.push(edit);
 4728                }
 4729            }
 4730            if !edits.is_empty() {
 4731                this.edit(edits, cx);
 4732            }
 4733            if !auto_indent_edits.is_empty() {
 4734                this.edit_with_autoindent(auto_indent_edits, cx);
 4735            }
 4736
 4737            let buffer = this.buffer.read(cx).snapshot(cx);
 4738            let new_selections = selection_info
 4739                .into_iter()
 4740                .map(|(extra_newline_inserted, new_selection)| {
 4741                    let mut cursor = new_selection.end.to_point(&buffer);
 4742                    if extra_newline_inserted {
 4743                        cursor.row -= 1;
 4744                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4745                    }
 4746                    new_selection.map(|_| cursor)
 4747                })
 4748                .collect();
 4749
 4750            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4751            this.refresh_edit_prediction(true, false, window, cx);
 4752        });
 4753    }
 4754
 4755    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4757
 4758        let buffer = self.buffer.read(cx);
 4759        let snapshot = buffer.snapshot(cx);
 4760
 4761        let mut edits = Vec::new();
 4762        let mut rows = Vec::new();
 4763
 4764        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4765            let cursor = selection.head();
 4766            let row = cursor.row;
 4767
 4768            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4769
 4770            let newline = "\n".to_string();
 4771            edits.push((start_of_line..start_of_line, newline));
 4772
 4773            rows.push(row + rows_inserted as u32);
 4774        }
 4775
 4776        self.transact(window, cx, |editor, window, cx| {
 4777            editor.edit(edits, cx);
 4778
 4779            editor.change_selections(Default::default(), window, cx, |s| {
 4780                let mut index = 0;
 4781                s.move_cursors_with(|map, _, _| {
 4782                    let row = rows[index];
 4783                    index += 1;
 4784
 4785                    let point = Point::new(row, 0);
 4786                    let boundary = map.next_line_boundary(point).1;
 4787                    let clipped = map.clip_point(boundary, Bias::Left);
 4788
 4789                    (clipped, SelectionGoal::None)
 4790                });
 4791            });
 4792
 4793            let mut indent_edits = Vec::new();
 4794            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4795            for row in rows {
 4796                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4797                for (row, indent) in indents {
 4798                    if indent.len == 0 {
 4799                        continue;
 4800                    }
 4801
 4802                    let text = match indent.kind {
 4803                        IndentKind::Space => " ".repeat(indent.len as usize),
 4804                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4805                    };
 4806                    let point = Point::new(row.0, 0);
 4807                    indent_edits.push((point..point, text));
 4808                }
 4809            }
 4810            editor.edit(indent_edits, cx);
 4811        });
 4812    }
 4813
 4814    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4816
 4817        let buffer = self.buffer.read(cx);
 4818        let snapshot = buffer.snapshot(cx);
 4819
 4820        let mut edits = Vec::new();
 4821        let mut rows = Vec::new();
 4822        let mut rows_inserted = 0;
 4823
 4824        for selection in self.selections.all_adjusted(cx) {
 4825            let cursor = selection.head();
 4826            let row = cursor.row;
 4827
 4828            let point = Point::new(row + 1, 0);
 4829            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4830
 4831            let newline = "\n".to_string();
 4832            edits.push((start_of_line..start_of_line, newline));
 4833
 4834            rows_inserted += 1;
 4835            rows.push(row + rows_inserted);
 4836        }
 4837
 4838        self.transact(window, cx, |editor, window, cx| {
 4839            editor.edit(edits, cx);
 4840
 4841            editor.change_selections(Default::default(), window, cx, |s| {
 4842                let mut index = 0;
 4843                s.move_cursors_with(|map, _, _| {
 4844                    let row = rows[index];
 4845                    index += 1;
 4846
 4847                    let point = Point::new(row, 0);
 4848                    let boundary = map.next_line_boundary(point).1;
 4849                    let clipped = map.clip_point(boundary, Bias::Left);
 4850
 4851                    (clipped, SelectionGoal::None)
 4852                });
 4853            });
 4854
 4855            let mut indent_edits = Vec::new();
 4856            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4857            for row in rows {
 4858                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4859                for (row, indent) in indents {
 4860                    if indent.len == 0 {
 4861                        continue;
 4862                    }
 4863
 4864                    let text = match indent.kind {
 4865                        IndentKind::Space => " ".repeat(indent.len as usize),
 4866                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4867                    };
 4868                    let point = Point::new(row.0, 0);
 4869                    indent_edits.push((point..point, text));
 4870                }
 4871            }
 4872            editor.edit(indent_edits, cx);
 4873        });
 4874    }
 4875
 4876    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4877        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4878            original_indent_columns: Vec::new(),
 4879        });
 4880        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4881    }
 4882
 4883    fn insert_with_autoindent_mode(
 4884        &mut self,
 4885        text: &str,
 4886        autoindent_mode: Option<AutoindentMode>,
 4887        window: &mut Window,
 4888        cx: &mut Context<Self>,
 4889    ) {
 4890        if self.read_only(cx) {
 4891            return;
 4892        }
 4893
 4894        let text: Arc<str> = text.into();
 4895        self.transact(window, cx, |this, window, cx| {
 4896            let old_selections = this.selections.all_adjusted(cx);
 4897            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4898                let anchors = {
 4899                    let snapshot = buffer.read(cx);
 4900                    old_selections
 4901                        .iter()
 4902                        .map(|s| {
 4903                            let anchor = snapshot.anchor_after(s.head());
 4904                            s.map(|_| anchor)
 4905                        })
 4906                        .collect::<Vec<_>>()
 4907                };
 4908                buffer.edit(
 4909                    old_selections
 4910                        .iter()
 4911                        .map(|s| (s.start..s.end, text.clone())),
 4912                    autoindent_mode,
 4913                    cx,
 4914                );
 4915                anchors
 4916            });
 4917
 4918            this.change_selections(Default::default(), window, cx, |s| {
 4919                s.select_anchors(selection_anchors);
 4920            });
 4921
 4922            cx.notify();
 4923        });
 4924    }
 4925
 4926    fn trigger_completion_on_input(
 4927        &mut self,
 4928        text: &str,
 4929        trigger_in_words: bool,
 4930        window: &mut Window,
 4931        cx: &mut Context<Self>,
 4932    ) {
 4933        let completions_source = self
 4934            .context_menu
 4935            .borrow()
 4936            .as_ref()
 4937            .and_then(|menu| match menu {
 4938                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4939                CodeContextMenu::CodeActions(_) => None,
 4940            });
 4941
 4942        match completions_source {
 4943            Some(CompletionsMenuSource::Words { .. }) => {
 4944                self.open_or_update_completions_menu(
 4945                    Some(CompletionsMenuSource::Words {
 4946                        ignore_threshold: false,
 4947                    }),
 4948                    None,
 4949                    window,
 4950                    cx,
 4951                );
 4952            }
 4953            Some(CompletionsMenuSource::Normal)
 4954            | Some(CompletionsMenuSource::SnippetChoices)
 4955            | None
 4956                if self.is_completion_trigger(
 4957                    text,
 4958                    trigger_in_words,
 4959                    completions_source.is_some(),
 4960                    cx,
 4961                ) =>
 4962            {
 4963                self.show_completions(
 4964                    &ShowCompletions {
 4965                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4966                    },
 4967                    window,
 4968                    cx,
 4969                )
 4970            }
 4971            _ => {
 4972                self.hide_context_menu(window, cx);
 4973            }
 4974        }
 4975    }
 4976
 4977    fn is_completion_trigger(
 4978        &self,
 4979        text: &str,
 4980        trigger_in_words: bool,
 4981        menu_is_open: bool,
 4982        cx: &mut Context<Self>,
 4983    ) -> bool {
 4984        let position = self.selections.newest_anchor().head();
 4985        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4986            return false;
 4987        };
 4988
 4989        if let Some(completion_provider) = &self.completion_provider {
 4990            completion_provider.is_completion_trigger(
 4991                &buffer,
 4992                position.text_anchor,
 4993                text,
 4994                trigger_in_words,
 4995                menu_is_open,
 4996                cx,
 4997            )
 4998        } else {
 4999            false
 5000        }
 5001    }
 5002
 5003    /// If any empty selections is touching the start of its innermost containing autoclose
 5004    /// region, expand it to select the brackets.
 5005    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5006        let selections = self.selections.all::<usize>(cx);
 5007        let buffer = self.buffer.read(cx).read(cx);
 5008        let new_selections = self
 5009            .selections_with_autoclose_regions(selections, &buffer)
 5010            .map(|(mut selection, region)| {
 5011                if !selection.is_empty() {
 5012                    return selection;
 5013                }
 5014
 5015                if let Some(region) = region {
 5016                    let mut range = region.range.to_offset(&buffer);
 5017                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5018                        range.start -= region.pair.start.len();
 5019                        if buffer.contains_str_at(range.start, &region.pair.start)
 5020                            && buffer.contains_str_at(range.end, &region.pair.end)
 5021                        {
 5022                            range.end += region.pair.end.len();
 5023                            selection.start = range.start;
 5024                            selection.end = range.end;
 5025
 5026                            return selection;
 5027                        }
 5028                    }
 5029                }
 5030
 5031                let always_treat_brackets_as_autoclosed = buffer
 5032                    .language_settings_at(selection.start, cx)
 5033                    .always_treat_brackets_as_autoclosed;
 5034
 5035                if !always_treat_brackets_as_autoclosed {
 5036                    return selection;
 5037                }
 5038
 5039                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5040                    for (pair, enabled) in scope.brackets() {
 5041                        if !enabled || !pair.close {
 5042                            continue;
 5043                        }
 5044
 5045                        if buffer.contains_str_at(selection.start, &pair.end) {
 5046                            let pair_start_len = pair.start.len();
 5047                            if buffer.contains_str_at(
 5048                                selection.start.saturating_sub(pair_start_len),
 5049                                &pair.start,
 5050                            ) {
 5051                                selection.start -= pair_start_len;
 5052                                selection.end += pair.end.len();
 5053
 5054                                return selection;
 5055                            }
 5056                        }
 5057                    }
 5058                }
 5059
 5060                selection
 5061            })
 5062            .collect();
 5063
 5064        drop(buffer);
 5065        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5066            selections.select(new_selections)
 5067        });
 5068    }
 5069
 5070    /// Iterate the given selections, and for each one, find the smallest surrounding
 5071    /// autoclose region. This uses the ordering of the selections and the autoclose
 5072    /// regions to avoid repeated comparisons.
 5073    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5074        &'a self,
 5075        selections: impl IntoIterator<Item = Selection<D>>,
 5076        buffer: &'a MultiBufferSnapshot,
 5077    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5078        let mut i = 0;
 5079        let mut regions = self.autoclose_regions.as_slice();
 5080        selections.into_iter().map(move |selection| {
 5081            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5082
 5083            let mut enclosing = None;
 5084            while let Some(pair_state) = regions.get(i) {
 5085                if pair_state.range.end.to_offset(buffer) < range.start {
 5086                    regions = &regions[i + 1..];
 5087                    i = 0;
 5088                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5089                    break;
 5090                } else {
 5091                    if pair_state.selection_id == selection.id {
 5092                        enclosing = Some(pair_state);
 5093                    }
 5094                    i += 1;
 5095                }
 5096            }
 5097
 5098            (selection, enclosing)
 5099        })
 5100    }
 5101
 5102    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5103    fn invalidate_autoclose_regions(
 5104        &mut self,
 5105        mut selections: &[Selection<Anchor>],
 5106        buffer: &MultiBufferSnapshot,
 5107    ) {
 5108        self.autoclose_regions.retain(|state| {
 5109            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5110                return false;
 5111            }
 5112
 5113            let mut i = 0;
 5114            while let Some(selection) = selections.get(i) {
 5115                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5116                    selections = &selections[1..];
 5117                    continue;
 5118                }
 5119                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5120                    break;
 5121                }
 5122                if selection.id == state.selection_id {
 5123                    return true;
 5124                } else {
 5125                    i += 1;
 5126                }
 5127            }
 5128            false
 5129        });
 5130    }
 5131
 5132    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5133        let offset = position.to_offset(buffer);
 5134        let (word_range, kind) =
 5135            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5136        if offset > word_range.start && kind == Some(CharKind::Word) {
 5137            Some(
 5138                buffer
 5139                    .text_for_range(word_range.start..offset)
 5140                    .collect::<String>(),
 5141            )
 5142        } else {
 5143            None
 5144        }
 5145    }
 5146
 5147    pub fn toggle_inline_values(
 5148        &mut self,
 5149        _: &ToggleInlineValues,
 5150        _: &mut Window,
 5151        cx: &mut Context<Self>,
 5152    ) {
 5153        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5154
 5155        self.refresh_inline_values(cx);
 5156    }
 5157
 5158    pub fn toggle_inlay_hints(
 5159        &mut self,
 5160        _: &ToggleInlayHints,
 5161        _: &mut Window,
 5162        cx: &mut Context<Self>,
 5163    ) {
 5164        self.refresh_inlay_hints(
 5165            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5166            cx,
 5167        );
 5168    }
 5169
 5170    pub fn inlay_hints_enabled(&self) -> bool {
 5171        self.inlay_hint_cache.enabled
 5172    }
 5173
 5174    pub fn inline_values_enabled(&self) -> bool {
 5175        self.inline_value_cache.enabled
 5176    }
 5177
 5178    #[cfg(any(test, feature = "test-support"))]
 5179    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5180        self.display_map
 5181            .read(cx)
 5182            .current_inlays()
 5183            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5184            .cloned()
 5185            .collect()
 5186    }
 5187
 5188    #[cfg(any(test, feature = "test-support"))]
 5189    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5190        self.display_map
 5191            .read(cx)
 5192            .current_inlays()
 5193            .cloned()
 5194            .collect()
 5195    }
 5196
 5197    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5198        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5199            return;
 5200        }
 5201
 5202        let reason_description = reason.description();
 5203        let ignore_debounce = matches!(
 5204            reason,
 5205            InlayHintRefreshReason::SettingsChange(_)
 5206                | InlayHintRefreshReason::Toggle(_)
 5207                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5208                | InlayHintRefreshReason::ModifiersChanged(_)
 5209        );
 5210        let (invalidate_cache, required_languages) = match reason {
 5211            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5212                match self.inlay_hint_cache.modifiers_override(enabled) {
 5213                    Some(enabled) => {
 5214                        if enabled {
 5215                            (InvalidationStrategy::RefreshRequested, None)
 5216                        } else {
 5217                            self.splice_inlays(
 5218                                &self
 5219                                    .visible_inlay_hints(cx)
 5220                                    .iter()
 5221                                    .map(|inlay| inlay.id)
 5222                                    .collect::<Vec<InlayId>>(),
 5223                                Vec::new(),
 5224                                cx,
 5225                            );
 5226                            return;
 5227                        }
 5228                    }
 5229                    None => return,
 5230                }
 5231            }
 5232            InlayHintRefreshReason::Toggle(enabled) => {
 5233                if self.inlay_hint_cache.toggle(enabled) {
 5234                    if enabled {
 5235                        (InvalidationStrategy::RefreshRequested, None)
 5236                    } else {
 5237                        self.splice_inlays(
 5238                            &self
 5239                                .visible_inlay_hints(cx)
 5240                                .iter()
 5241                                .map(|inlay| inlay.id)
 5242                                .collect::<Vec<InlayId>>(),
 5243                            Vec::new(),
 5244                            cx,
 5245                        );
 5246                        return;
 5247                    }
 5248                } else {
 5249                    return;
 5250                }
 5251            }
 5252            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5253                match self.inlay_hint_cache.update_settings(
 5254                    &self.buffer,
 5255                    new_settings,
 5256                    self.visible_inlay_hints(cx),
 5257                    cx,
 5258                ) {
 5259                    ControlFlow::Break(Some(InlaySplice {
 5260                        to_remove,
 5261                        to_insert,
 5262                    })) => {
 5263                        self.splice_inlays(&to_remove, to_insert, cx);
 5264                        return;
 5265                    }
 5266                    ControlFlow::Break(None) => return,
 5267                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5268                }
 5269            }
 5270            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5271                if let Some(InlaySplice {
 5272                    to_remove,
 5273                    to_insert,
 5274                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5275                {
 5276                    self.splice_inlays(&to_remove, to_insert, cx);
 5277                }
 5278                self.display_map.update(cx, |display_map, _| {
 5279                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5280                });
 5281                return;
 5282            }
 5283            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5284            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5285                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5286            }
 5287            InlayHintRefreshReason::RefreshRequested => {
 5288                (InvalidationStrategy::RefreshRequested, None)
 5289            }
 5290        };
 5291
 5292        if let Some(InlaySplice {
 5293            to_remove,
 5294            to_insert,
 5295        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5296            reason_description,
 5297            self.visible_excerpts(required_languages.as_ref(), cx),
 5298            invalidate_cache,
 5299            ignore_debounce,
 5300            cx,
 5301        ) {
 5302            self.splice_inlays(&to_remove, to_insert, cx);
 5303        }
 5304    }
 5305
 5306    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5307        self.display_map
 5308            .read(cx)
 5309            .current_inlays()
 5310            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5311            .cloned()
 5312            .collect()
 5313    }
 5314
 5315    pub fn visible_excerpts(
 5316        &self,
 5317        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5318        cx: &mut Context<Editor>,
 5319    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5320        let Some(project) = self.project() else {
 5321            return HashMap::default();
 5322        };
 5323        let project = project.read(cx);
 5324        let multi_buffer = self.buffer().read(cx);
 5325        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5326        let multi_buffer_visible_start = self
 5327            .scroll_manager
 5328            .anchor()
 5329            .anchor
 5330            .to_point(&multi_buffer_snapshot);
 5331        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5332            multi_buffer_visible_start
 5333                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5334            Bias::Left,
 5335        );
 5336        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5337        multi_buffer_snapshot
 5338            .range_to_buffer_ranges(multi_buffer_visible_range)
 5339            .into_iter()
 5340            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5341            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5342                let buffer_file = project::File::from_dyn(buffer.file())?;
 5343                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5344                let worktree_entry = buffer_worktree
 5345                    .read(cx)
 5346                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5347                if worktree_entry.is_ignored {
 5348                    return None;
 5349                }
 5350
 5351                let language = buffer.language()?;
 5352                if let Some(restrict_to_languages) = restrict_to_languages
 5353                    && !restrict_to_languages.contains(language)
 5354                {
 5355                    return None;
 5356                }
 5357                Some((
 5358                    excerpt_id,
 5359                    (
 5360                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5361                        buffer.version().clone(),
 5362                        excerpt_visible_range,
 5363                    ),
 5364                ))
 5365            })
 5366            .collect()
 5367    }
 5368
 5369    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5370        TextLayoutDetails {
 5371            text_system: window.text_system().clone(),
 5372            editor_style: self.style.clone().unwrap(),
 5373            rem_size: window.rem_size(),
 5374            scroll_anchor: self.scroll_manager.anchor(),
 5375            visible_rows: self.visible_line_count(),
 5376            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5377        }
 5378    }
 5379
 5380    pub fn splice_inlays(
 5381        &self,
 5382        to_remove: &[InlayId],
 5383        to_insert: Vec<Inlay>,
 5384        cx: &mut Context<Self>,
 5385    ) {
 5386        self.display_map.update(cx, |display_map, cx| {
 5387            display_map.splice_inlays(to_remove, to_insert, cx)
 5388        });
 5389        cx.notify();
 5390    }
 5391
 5392    fn trigger_on_type_formatting(
 5393        &self,
 5394        input: String,
 5395        window: &mut Window,
 5396        cx: &mut Context<Self>,
 5397    ) -> Option<Task<Result<()>>> {
 5398        if input.len() != 1 {
 5399            return None;
 5400        }
 5401
 5402        let project = self.project()?;
 5403        let position = self.selections.newest_anchor().head();
 5404        let (buffer, buffer_position) = self
 5405            .buffer
 5406            .read(cx)
 5407            .text_anchor_for_position(position, cx)?;
 5408
 5409        let settings = language_settings::language_settings(
 5410            buffer
 5411                .read(cx)
 5412                .language_at(buffer_position)
 5413                .map(|l| l.name()),
 5414            buffer.read(cx).file(),
 5415            cx,
 5416        );
 5417        if !settings.use_on_type_format {
 5418            return None;
 5419        }
 5420
 5421        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5422        // hence we do LSP request & edit on host side only — add formats to host's history.
 5423        let push_to_lsp_host_history = true;
 5424        // If this is not the host, append its history with new edits.
 5425        let push_to_client_history = project.read(cx).is_via_collab();
 5426
 5427        let on_type_formatting = project.update(cx, |project, cx| {
 5428            project.on_type_format(
 5429                buffer.clone(),
 5430                buffer_position,
 5431                input,
 5432                push_to_lsp_host_history,
 5433                cx,
 5434            )
 5435        });
 5436        Some(cx.spawn_in(window, async move |editor, cx| {
 5437            if let Some(transaction) = on_type_formatting.await? {
 5438                if push_to_client_history {
 5439                    buffer
 5440                        .update(cx, |buffer, _| {
 5441                            buffer.push_transaction(transaction, Instant::now());
 5442                            buffer.finalize_last_transaction();
 5443                        })
 5444                        .ok();
 5445                }
 5446                editor.update(cx, |editor, cx| {
 5447                    editor.refresh_document_highlights(cx);
 5448                })?;
 5449            }
 5450            Ok(())
 5451        }))
 5452    }
 5453
 5454    pub fn show_word_completions(
 5455        &mut self,
 5456        _: &ShowWordCompletions,
 5457        window: &mut Window,
 5458        cx: &mut Context<Self>,
 5459    ) {
 5460        self.open_or_update_completions_menu(
 5461            Some(CompletionsMenuSource::Words {
 5462                ignore_threshold: true,
 5463            }),
 5464            None,
 5465            window,
 5466            cx,
 5467        );
 5468    }
 5469
 5470    pub fn show_completions(
 5471        &mut self,
 5472        options: &ShowCompletions,
 5473        window: &mut Window,
 5474        cx: &mut Context<Self>,
 5475    ) {
 5476        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5477    }
 5478
 5479    fn open_or_update_completions_menu(
 5480        &mut self,
 5481        requested_source: Option<CompletionsMenuSource>,
 5482        trigger: Option<&str>,
 5483        window: &mut Window,
 5484        cx: &mut Context<Self>,
 5485    ) {
 5486        if self.pending_rename.is_some() {
 5487            return;
 5488        }
 5489
 5490        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5491
 5492        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5493        // inserted and selected. To handle that case, the start of the selection is used so that
 5494        // the menu starts with all choices.
 5495        let position = self
 5496            .selections
 5497            .newest_anchor()
 5498            .start
 5499            .bias_right(&multibuffer_snapshot);
 5500        if position.diff_base_anchor.is_some() {
 5501            return;
 5502        }
 5503        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5504        let Some(buffer) = buffer_position
 5505            .buffer_id
 5506            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5507        else {
 5508            return;
 5509        };
 5510        let buffer_snapshot = buffer.read(cx).snapshot();
 5511
 5512        let query: Option<Arc<String>> =
 5513            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5514                .map(|query| query.into());
 5515
 5516        drop(multibuffer_snapshot);
 5517
 5518        // Hide the current completions menu when query is empty. Without this, cached
 5519        // completions from before the trigger char may be reused (#32774).
 5520        if query.is_none() {
 5521            let menu_is_open = matches!(
 5522                self.context_menu.borrow().as_ref(),
 5523                Some(CodeContextMenu::Completions(_))
 5524            );
 5525            if menu_is_open {
 5526                self.hide_context_menu(window, cx);
 5527            }
 5528        }
 5529
 5530        let mut ignore_word_threshold = false;
 5531        let provider = match requested_source {
 5532            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5533            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5534                ignore_word_threshold = ignore_threshold;
 5535                None
 5536            }
 5537            Some(CompletionsMenuSource::SnippetChoices) => {
 5538                log::error!("bug: SnippetChoices requested_source is not handled");
 5539                None
 5540            }
 5541        };
 5542
 5543        let sort_completions = provider
 5544            .as_ref()
 5545            .is_some_and(|provider| provider.sort_completions());
 5546
 5547        let filter_completions = provider
 5548            .as_ref()
 5549            .is_none_or(|provider| provider.filter_completions());
 5550
 5551        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5552            if filter_completions {
 5553                menu.filter(query.clone(), provider.clone(), window, cx);
 5554            }
 5555            // When `is_incomplete` is false, no need to re-query completions when the current query
 5556            // is a suffix of the initial query.
 5557            if !menu.is_incomplete {
 5558                // If the new query is a suffix of the old query (typing more characters) and
 5559                // the previous result was complete, the existing completions can be filtered.
 5560                //
 5561                // Note that this is always true for snippet completions.
 5562                let query_matches = match (&menu.initial_query, &query) {
 5563                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5564                    (None, _) => true,
 5565                    _ => false,
 5566                };
 5567                if query_matches {
 5568                    let position_matches = if menu.initial_position == position {
 5569                        true
 5570                    } else {
 5571                        let snapshot = self.buffer.read(cx).read(cx);
 5572                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5573                    };
 5574                    if position_matches {
 5575                        return;
 5576                    }
 5577                }
 5578            }
 5579        };
 5580
 5581        let trigger_kind = match trigger {
 5582            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5583                CompletionTriggerKind::TRIGGER_CHARACTER
 5584            }
 5585            _ => CompletionTriggerKind::INVOKED,
 5586        };
 5587        let completion_context = CompletionContext {
 5588            trigger_character: trigger.and_then(|trigger| {
 5589                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5590                    Some(String::from(trigger))
 5591                } else {
 5592                    None
 5593                }
 5594            }),
 5595            trigger_kind,
 5596        };
 5597
 5598        let Anchor {
 5599            excerpt_id: buffer_excerpt_id,
 5600            text_anchor: buffer_position,
 5601            ..
 5602        } = buffer_position;
 5603
 5604        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5605            buffer_snapshot.surrounding_word(buffer_position, None)
 5606        {
 5607            let word_to_exclude = buffer_snapshot
 5608                .text_for_range(word_range.clone())
 5609                .collect::<String>();
 5610            (
 5611                buffer_snapshot.anchor_before(word_range.start)
 5612                    ..buffer_snapshot.anchor_after(buffer_position),
 5613                Some(word_to_exclude),
 5614            )
 5615        } else {
 5616            (buffer_position..buffer_position, None)
 5617        };
 5618
 5619        let language = buffer_snapshot
 5620            .language_at(buffer_position)
 5621            .map(|language| language.name());
 5622
 5623        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5624            .completions
 5625            .clone();
 5626
 5627        let show_completion_documentation = buffer_snapshot
 5628            .settings_at(buffer_position, cx)
 5629            .show_completion_documentation;
 5630
 5631        // The document can be large, so stay in reasonable bounds when searching for words,
 5632        // otherwise completion pop-up might be slow to appear.
 5633        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5634        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5635        let min_word_search = buffer_snapshot.clip_point(
 5636            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5637            Bias::Left,
 5638        );
 5639        let max_word_search = buffer_snapshot.clip_point(
 5640            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5641            Bias::Right,
 5642        );
 5643        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5644            ..buffer_snapshot.point_to_offset(max_word_search);
 5645
 5646        let skip_digits = query
 5647            .as_ref()
 5648            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5649
 5650        let omit_word_completions = !self.word_completions_enabled
 5651            || (!ignore_word_threshold
 5652                && match &query {
 5653                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5654                    None => completion_settings.words_min_length != 0,
 5655                });
 5656
 5657        let (mut words, provider_responses) = match &provider {
 5658            Some(provider) => {
 5659                let provider_responses = provider.completions(
 5660                    buffer_excerpt_id,
 5661                    &buffer,
 5662                    buffer_position,
 5663                    completion_context,
 5664                    window,
 5665                    cx,
 5666                );
 5667
 5668                let words = match (omit_word_completions, completion_settings.words) {
 5669                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5670                        Task::ready(BTreeMap::default())
 5671                    }
 5672                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5673                        .background_spawn(async move {
 5674                            buffer_snapshot.words_in_range(WordsQuery {
 5675                                fuzzy_contents: None,
 5676                                range: word_search_range,
 5677                                skip_digits,
 5678                            })
 5679                        }),
 5680                };
 5681
 5682                (words, provider_responses)
 5683            }
 5684            None => {
 5685                let words = if omit_word_completions {
 5686                    Task::ready(BTreeMap::default())
 5687                } else {
 5688                    cx.background_spawn(async move {
 5689                        buffer_snapshot.words_in_range(WordsQuery {
 5690                            fuzzy_contents: None,
 5691                            range: word_search_range,
 5692                            skip_digits,
 5693                        })
 5694                    })
 5695                };
 5696                (words, Task::ready(Ok(Vec::new())))
 5697            }
 5698        };
 5699
 5700        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5701
 5702        let id = post_inc(&mut self.next_completion_id);
 5703        let task = cx.spawn_in(window, async move |editor, cx| {
 5704            let Ok(()) = editor.update(cx, |this, _| {
 5705                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5706            }) else {
 5707                return;
 5708            };
 5709
 5710            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5711            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5712            let mut completions = Vec::new();
 5713            let mut is_incomplete = false;
 5714            let mut display_options: Option<CompletionDisplayOptions> = None;
 5715            if let Some(provider_responses) = provider_responses.await.log_err()
 5716                && !provider_responses.is_empty()
 5717            {
 5718                for response in provider_responses {
 5719                    completions.extend(response.completions);
 5720                    is_incomplete = is_incomplete || response.is_incomplete;
 5721                    match display_options.as_mut() {
 5722                        None => {
 5723                            display_options = Some(response.display_options);
 5724                        }
 5725                        Some(options) => options.merge(&response.display_options),
 5726                    }
 5727                }
 5728                if completion_settings.words == WordsCompletionMode::Fallback {
 5729                    words = Task::ready(BTreeMap::default());
 5730                }
 5731            }
 5732            let display_options = display_options.unwrap_or_default();
 5733
 5734            let mut words = words.await;
 5735            if let Some(word_to_exclude) = &word_to_exclude {
 5736                words.remove(word_to_exclude);
 5737            }
 5738            for lsp_completion in &completions {
 5739                words.remove(&lsp_completion.new_text);
 5740            }
 5741            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5742                replace_range: word_replace_range.clone(),
 5743                new_text: word.clone(),
 5744                label: CodeLabel::plain(word, None),
 5745                icon_path: None,
 5746                documentation: None,
 5747                source: CompletionSource::BufferWord {
 5748                    word_range,
 5749                    resolved: false,
 5750                },
 5751                insert_text_mode: Some(InsertTextMode::AS_IS),
 5752                confirm: None,
 5753            }));
 5754
 5755            let menu = if completions.is_empty() {
 5756                None
 5757            } else {
 5758                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5759                    let languages = editor
 5760                        .workspace
 5761                        .as_ref()
 5762                        .and_then(|(workspace, _)| workspace.upgrade())
 5763                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5764                    let menu = CompletionsMenu::new(
 5765                        id,
 5766                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5767                        sort_completions,
 5768                        show_completion_documentation,
 5769                        position,
 5770                        query.clone(),
 5771                        is_incomplete,
 5772                        buffer.clone(),
 5773                        completions.into(),
 5774                        display_options,
 5775                        snippet_sort_order,
 5776                        languages,
 5777                        language,
 5778                        cx,
 5779                    );
 5780
 5781                    let query = if filter_completions { query } else { None };
 5782                    let matches_task = if let Some(query) = query {
 5783                        menu.do_async_filtering(query, cx)
 5784                    } else {
 5785                        Task::ready(menu.unfiltered_matches())
 5786                    };
 5787                    (menu, matches_task)
 5788                }) else {
 5789                    return;
 5790                };
 5791
 5792                let matches = matches_task.await;
 5793
 5794                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5795                    // Newer menu already set, so exit.
 5796                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5797                        editor.context_menu.borrow().as_ref()
 5798                        && prev_menu.id > id
 5799                    {
 5800                        return;
 5801                    };
 5802
 5803                    // Only valid to take prev_menu because it the new menu is immediately set
 5804                    // below, or the menu is hidden.
 5805                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5806                        editor.context_menu.borrow_mut().take()
 5807                    {
 5808                        let position_matches =
 5809                            if prev_menu.initial_position == menu.initial_position {
 5810                                true
 5811                            } else {
 5812                                let snapshot = editor.buffer.read(cx).read(cx);
 5813                                prev_menu.initial_position.to_offset(&snapshot)
 5814                                    == menu.initial_position.to_offset(&snapshot)
 5815                            };
 5816                        if position_matches {
 5817                            // Preserve markdown cache before `set_filter_results` because it will
 5818                            // try to populate the documentation cache.
 5819                            menu.preserve_markdown_cache(prev_menu);
 5820                        }
 5821                    };
 5822
 5823                    menu.set_filter_results(matches, provider, window, cx);
 5824                }) else {
 5825                    return;
 5826                };
 5827
 5828                menu.visible().then_some(menu)
 5829            };
 5830
 5831            editor
 5832                .update_in(cx, |editor, window, cx| {
 5833                    if editor.focus_handle.is_focused(window)
 5834                        && let Some(menu) = menu
 5835                    {
 5836                        *editor.context_menu.borrow_mut() =
 5837                            Some(CodeContextMenu::Completions(menu));
 5838
 5839                        crate::hover_popover::hide_hover(editor, cx);
 5840                        if editor.show_edit_predictions_in_menu() {
 5841                            editor.update_visible_edit_prediction(window, cx);
 5842                        } else {
 5843                            editor.discard_edit_prediction(false, cx);
 5844                        }
 5845
 5846                        cx.notify();
 5847                        return;
 5848                    }
 5849
 5850                    if editor.completion_tasks.len() <= 1 {
 5851                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5852                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5853                        // If it was already hidden and we don't show edit predictions in the menu,
 5854                        // we should also show the edit prediction when available.
 5855                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5856                            editor.update_visible_edit_prediction(window, cx);
 5857                        }
 5858                    }
 5859                })
 5860                .ok();
 5861        });
 5862
 5863        self.completion_tasks.push((id, task));
 5864    }
 5865
 5866    #[cfg(feature = "test-support")]
 5867    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5868        let menu = self.context_menu.borrow();
 5869        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5870            let completions = menu.completions.borrow();
 5871            Some(completions.to_vec())
 5872        } else {
 5873            None
 5874        }
 5875    }
 5876
 5877    pub fn with_completions_menu_matching_id<R>(
 5878        &self,
 5879        id: CompletionId,
 5880        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5881    ) -> R {
 5882        let mut context_menu = self.context_menu.borrow_mut();
 5883        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5884            return f(None);
 5885        };
 5886        if completions_menu.id != id {
 5887            return f(None);
 5888        }
 5889        f(Some(completions_menu))
 5890    }
 5891
 5892    pub fn confirm_completion(
 5893        &mut self,
 5894        action: &ConfirmCompletion,
 5895        window: &mut Window,
 5896        cx: &mut Context<Self>,
 5897    ) -> Option<Task<Result<()>>> {
 5898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5899        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5900    }
 5901
 5902    pub fn confirm_completion_insert(
 5903        &mut self,
 5904        _: &ConfirmCompletionInsert,
 5905        window: &mut Window,
 5906        cx: &mut Context<Self>,
 5907    ) -> Option<Task<Result<()>>> {
 5908        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5909        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5910    }
 5911
 5912    pub fn confirm_completion_replace(
 5913        &mut self,
 5914        _: &ConfirmCompletionReplace,
 5915        window: &mut Window,
 5916        cx: &mut Context<Self>,
 5917    ) -> Option<Task<Result<()>>> {
 5918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5919        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5920    }
 5921
 5922    pub fn compose_completion(
 5923        &mut self,
 5924        action: &ComposeCompletion,
 5925        window: &mut Window,
 5926        cx: &mut Context<Self>,
 5927    ) -> Option<Task<Result<()>>> {
 5928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5929        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5930    }
 5931
 5932    fn do_completion(
 5933        &mut self,
 5934        item_ix: Option<usize>,
 5935        intent: CompletionIntent,
 5936        window: &mut Window,
 5937        cx: &mut Context<Editor>,
 5938    ) -> Option<Task<Result<()>>> {
 5939        use language::ToOffset as _;
 5940
 5941        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5942        else {
 5943            return None;
 5944        };
 5945
 5946        let candidate_id = {
 5947            let entries = completions_menu.entries.borrow();
 5948            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5949            if self.show_edit_predictions_in_menu() {
 5950                self.discard_edit_prediction(true, cx);
 5951            }
 5952            mat.candidate_id
 5953        };
 5954
 5955        let completion = completions_menu
 5956            .completions
 5957            .borrow()
 5958            .get(candidate_id)?
 5959            .clone();
 5960        cx.stop_propagation();
 5961
 5962        let buffer_handle = completions_menu.buffer.clone();
 5963
 5964        let CompletionEdit {
 5965            new_text,
 5966            snippet,
 5967            replace_range,
 5968        } = process_completion_for_edit(
 5969            &completion,
 5970            intent,
 5971            &buffer_handle,
 5972            &completions_menu.initial_position.text_anchor,
 5973            cx,
 5974        );
 5975
 5976        let buffer = buffer_handle.read(cx);
 5977        let snapshot = self.buffer.read(cx).snapshot(cx);
 5978        let newest_anchor = self.selections.newest_anchor();
 5979        let replace_range_multibuffer = {
 5980            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5981            let multibuffer_anchor = snapshot
 5982                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5983                .unwrap()
 5984                ..snapshot
 5985                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5986                    .unwrap();
 5987            multibuffer_anchor.start.to_offset(&snapshot)
 5988                ..multibuffer_anchor.end.to_offset(&snapshot)
 5989        };
 5990        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5991            return None;
 5992        }
 5993
 5994        let old_text = buffer
 5995            .text_for_range(replace_range.clone())
 5996            .collect::<String>();
 5997        let lookbehind = newest_anchor
 5998            .start
 5999            .text_anchor
 6000            .to_offset(buffer)
 6001            .saturating_sub(replace_range.start);
 6002        let lookahead = replace_range
 6003            .end
 6004            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6005        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6006        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6007
 6008        let selections = self.selections.all::<usize>(cx);
 6009        let mut ranges = Vec::new();
 6010        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6011
 6012        for selection in &selections {
 6013            let range = if selection.id == newest_anchor.id {
 6014                replace_range_multibuffer.clone()
 6015            } else {
 6016                let mut range = selection.range();
 6017
 6018                // if prefix is present, don't duplicate it
 6019                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6020                    range.start = range.start.saturating_sub(lookbehind);
 6021
 6022                    // if suffix is also present, mimic the newest cursor and replace it
 6023                    if selection.id != newest_anchor.id
 6024                        && snapshot.contains_str_at(range.end, suffix)
 6025                    {
 6026                        range.end += lookahead;
 6027                    }
 6028                }
 6029                range
 6030            };
 6031
 6032            ranges.push(range.clone());
 6033
 6034            if !self.linked_edit_ranges.is_empty() {
 6035                let start_anchor = snapshot.anchor_before(range.start);
 6036                let end_anchor = snapshot.anchor_after(range.end);
 6037                if let Some(ranges) = self
 6038                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6039                {
 6040                    for (buffer, edits) in ranges {
 6041                        linked_edits
 6042                            .entry(buffer.clone())
 6043                            .or_default()
 6044                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6045                    }
 6046                }
 6047            }
 6048        }
 6049
 6050        let common_prefix_len = old_text
 6051            .chars()
 6052            .zip(new_text.chars())
 6053            .take_while(|(a, b)| a == b)
 6054            .map(|(a, _)| a.len_utf8())
 6055            .sum::<usize>();
 6056
 6057        cx.emit(EditorEvent::InputHandled {
 6058            utf16_range_to_replace: None,
 6059            text: new_text[common_prefix_len..].into(),
 6060        });
 6061
 6062        self.transact(window, cx, |editor, window, cx| {
 6063            if let Some(mut snippet) = snippet {
 6064                snippet.text = new_text.to_string();
 6065                editor
 6066                    .insert_snippet(&ranges, snippet, window, cx)
 6067                    .log_err();
 6068            } else {
 6069                editor.buffer.update(cx, |multi_buffer, cx| {
 6070                    let auto_indent = match completion.insert_text_mode {
 6071                        Some(InsertTextMode::AS_IS) => None,
 6072                        _ => editor.autoindent_mode.clone(),
 6073                    };
 6074                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6075                    multi_buffer.edit(edits, auto_indent, cx);
 6076                });
 6077            }
 6078            for (buffer, edits) in linked_edits {
 6079                buffer.update(cx, |buffer, cx| {
 6080                    let snapshot = buffer.snapshot();
 6081                    let edits = edits
 6082                        .into_iter()
 6083                        .map(|(range, text)| {
 6084                            use text::ToPoint as TP;
 6085                            let end_point = TP::to_point(&range.end, &snapshot);
 6086                            let start_point = TP::to_point(&range.start, &snapshot);
 6087                            (start_point..end_point, text)
 6088                        })
 6089                        .sorted_by_key(|(range, _)| range.start);
 6090                    buffer.edit(edits, None, cx);
 6091                })
 6092            }
 6093
 6094            editor.refresh_edit_prediction(true, false, window, cx);
 6095        });
 6096        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6097
 6098        let show_new_completions_on_confirm = completion
 6099            .confirm
 6100            .as_ref()
 6101            .is_some_and(|confirm| confirm(intent, window, cx));
 6102        if show_new_completions_on_confirm {
 6103            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6104        }
 6105
 6106        let provider = self.completion_provider.as_ref()?;
 6107        drop(completion);
 6108        let apply_edits = provider.apply_additional_edits_for_completion(
 6109            buffer_handle,
 6110            completions_menu.completions.clone(),
 6111            candidate_id,
 6112            true,
 6113            cx,
 6114        );
 6115
 6116        let editor_settings = EditorSettings::get_global(cx);
 6117        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6118            // After the code completion is finished, users often want to know what signatures are needed.
 6119            // so we should automatically call signature_help
 6120            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6121        }
 6122
 6123        Some(cx.foreground_executor().spawn(async move {
 6124            apply_edits.await?;
 6125            Ok(())
 6126        }))
 6127    }
 6128
 6129    pub fn toggle_code_actions(
 6130        &mut self,
 6131        action: &ToggleCodeActions,
 6132        window: &mut Window,
 6133        cx: &mut Context<Self>,
 6134    ) {
 6135        let quick_launch = action.quick_launch;
 6136        let mut context_menu = self.context_menu.borrow_mut();
 6137        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6138            if code_actions.deployed_from == action.deployed_from {
 6139                // Toggle if we're selecting the same one
 6140                *context_menu = None;
 6141                cx.notify();
 6142                return;
 6143            } else {
 6144                // Otherwise, clear it and start a new one
 6145                *context_menu = None;
 6146                cx.notify();
 6147            }
 6148        }
 6149        drop(context_menu);
 6150        let snapshot = self.snapshot(window, cx);
 6151        let deployed_from = action.deployed_from.clone();
 6152        let action = action.clone();
 6153        self.completion_tasks.clear();
 6154        self.discard_edit_prediction(false, cx);
 6155
 6156        let multibuffer_point = match &action.deployed_from {
 6157            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6158                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6159            }
 6160            _ => self.selections.newest::<Point>(cx).head(),
 6161        };
 6162        let Some((buffer, buffer_row)) = snapshot
 6163            .buffer_snapshot()
 6164            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6165            .and_then(|(buffer_snapshot, range)| {
 6166                self.buffer()
 6167                    .read(cx)
 6168                    .buffer(buffer_snapshot.remote_id())
 6169                    .map(|buffer| (buffer, range.start.row))
 6170            })
 6171        else {
 6172            return;
 6173        };
 6174        let buffer_id = buffer.read(cx).remote_id();
 6175        let tasks = self
 6176            .tasks
 6177            .get(&(buffer_id, buffer_row))
 6178            .map(|t| Arc::new(t.to_owned()));
 6179
 6180        if !self.focus_handle.is_focused(window) {
 6181            return;
 6182        }
 6183        let project = self.project.clone();
 6184
 6185        let code_actions_task = match deployed_from {
 6186            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6187            _ => self.code_actions(buffer_row, window, cx),
 6188        };
 6189
 6190        let runnable_task = match deployed_from {
 6191            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6192            _ => {
 6193                let mut task_context_task = Task::ready(None);
 6194                if let Some(tasks) = &tasks
 6195                    && let Some(project) = project
 6196                {
 6197                    task_context_task =
 6198                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6199                }
 6200
 6201                cx.spawn_in(window, {
 6202                    let buffer = buffer.clone();
 6203                    async move |editor, cx| {
 6204                        let task_context = task_context_task.await;
 6205
 6206                        let resolved_tasks =
 6207                            tasks
 6208                                .zip(task_context.clone())
 6209                                .map(|(tasks, task_context)| ResolvedTasks {
 6210                                    templates: tasks.resolve(&task_context).collect(),
 6211                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6212                                        multibuffer_point.row,
 6213                                        tasks.column,
 6214                                    )),
 6215                                });
 6216                        let debug_scenarios = editor
 6217                            .update(cx, |editor, cx| {
 6218                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6219                            })?
 6220                            .await;
 6221                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6222                    }
 6223                })
 6224            }
 6225        };
 6226
 6227        cx.spawn_in(window, async move |editor, cx| {
 6228            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6229            let code_actions = code_actions_task.await;
 6230            let spawn_straight_away = quick_launch
 6231                && resolved_tasks
 6232                    .as_ref()
 6233                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6234                && code_actions
 6235                    .as_ref()
 6236                    .is_none_or(|actions| actions.is_empty())
 6237                && debug_scenarios.is_empty();
 6238
 6239            editor.update_in(cx, |editor, window, cx| {
 6240                crate::hover_popover::hide_hover(editor, cx);
 6241                let actions = CodeActionContents::new(
 6242                    resolved_tasks,
 6243                    code_actions,
 6244                    debug_scenarios,
 6245                    task_context.unwrap_or_default(),
 6246                );
 6247
 6248                // Don't show the menu if there are no actions available
 6249                if actions.is_empty() {
 6250                    cx.notify();
 6251                    return Task::ready(Ok(()));
 6252                }
 6253
 6254                *editor.context_menu.borrow_mut() =
 6255                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6256                        buffer,
 6257                        actions,
 6258                        selected_item: Default::default(),
 6259                        scroll_handle: UniformListScrollHandle::default(),
 6260                        deployed_from,
 6261                    }));
 6262                cx.notify();
 6263                if spawn_straight_away
 6264                    && let Some(task) = editor.confirm_code_action(
 6265                        &ConfirmCodeAction { item_ix: Some(0) },
 6266                        window,
 6267                        cx,
 6268                    )
 6269                {
 6270                    return task;
 6271                }
 6272
 6273                Task::ready(Ok(()))
 6274            })
 6275        })
 6276        .detach_and_log_err(cx);
 6277    }
 6278
 6279    fn debug_scenarios(
 6280        &mut self,
 6281        resolved_tasks: &Option<ResolvedTasks>,
 6282        buffer: &Entity<Buffer>,
 6283        cx: &mut App,
 6284    ) -> Task<Vec<task::DebugScenario>> {
 6285        maybe!({
 6286            let project = self.project()?;
 6287            let dap_store = project.read(cx).dap_store();
 6288            let mut scenarios = vec![];
 6289            let resolved_tasks = resolved_tasks.as_ref()?;
 6290            let buffer = buffer.read(cx);
 6291            let language = buffer.language()?;
 6292            let file = buffer.file();
 6293            let debug_adapter = language_settings(language.name().into(), file, cx)
 6294                .debuggers
 6295                .first()
 6296                .map(SharedString::from)
 6297                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6298
 6299            dap_store.update(cx, |dap_store, cx| {
 6300                for (_, task) in &resolved_tasks.templates {
 6301                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6302                        task.original_task().clone(),
 6303                        debug_adapter.clone().into(),
 6304                        task.display_label().to_owned().into(),
 6305                        cx,
 6306                    );
 6307                    scenarios.push(maybe_scenario);
 6308                }
 6309            });
 6310            Some(cx.background_spawn(async move {
 6311                futures::future::join_all(scenarios)
 6312                    .await
 6313                    .into_iter()
 6314                    .flatten()
 6315                    .collect::<Vec<_>>()
 6316            }))
 6317        })
 6318        .unwrap_or_else(|| Task::ready(vec![]))
 6319    }
 6320
 6321    fn code_actions(
 6322        &mut self,
 6323        buffer_row: u32,
 6324        window: &mut Window,
 6325        cx: &mut Context<Self>,
 6326    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6327        let mut task = self.code_actions_task.take();
 6328        cx.spawn_in(window, async move |editor, cx| {
 6329            while let Some(prev_task) = task {
 6330                prev_task.await.log_err();
 6331                task = editor
 6332                    .update(cx, |this, _| this.code_actions_task.take())
 6333                    .ok()?;
 6334            }
 6335
 6336            editor
 6337                .update(cx, |editor, cx| {
 6338                    editor
 6339                        .available_code_actions
 6340                        .clone()
 6341                        .and_then(|(location, code_actions)| {
 6342                            let snapshot = location.buffer.read(cx).snapshot();
 6343                            let point_range = location.range.to_point(&snapshot);
 6344                            let point_range = point_range.start.row..=point_range.end.row;
 6345                            if point_range.contains(&buffer_row) {
 6346                                Some(code_actions)
 6347                            } else {
 6348                                None
 6349                            }
 6350                        })
 6351                })
 6352                .ok()
 6353                .flatten()
 6354        })
 6355    }
 6356
 6357    pub fn confirm_code_action(
 6358        &mut self,
 6359        action: &ConfirmCodeAction,
 6360        window: &mut Window,
 6361        cx: &mut Context<Self>,
 6362    ) -> Option<Task<Result<()>>> {
 6363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6364
 6365        let actions_menu =
 6366            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6367                menu
 6368            } else {
 6369                return None;
 6370            };
 6371
 6372        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6373        let action = actions_menu.actions.get(action_ix)?;
 6374        let title = action.label();
 6375        let buffer = actions_menu.buffer;
 6376        let workspace = self.workspace()?;
 6377
 6378        match action {
 6379            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6380                workspace.update(cx, |workspace, cx| {
 6381                    workspace.schedule_resolved_task(
 6382                        task_source_kind,
 6383                        resolved_task,
 6384                        false,
 6385                        window,
 6386                        cx,
 6387                    );
 6388
 6389                    Some(Task::ready(Ok(())))
 6390                })
 6391            }
 6392            CodeActionsItem::CodeAction {
 6393                excerpt_id,
 6394                action,
 6395                provider,
 6396            } => {
 6397                let apply_code_action =
 6398                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6399                let workspace = workspace.downgrade();
 6400                Some(cx.spawn_in(window, async move |editor, cx| {
 6401                    let project_transaction = apply_code_action.await?;
 6402                    Self::open_project_transaction(
 6403                        &editor,
 6404                        workspace,
 6405                        project_transaction,
 6406                        title,
 6407                        cx,
 6408                    )
 6409                    .await
 6410                }))
 6411            }
 6412            CodeActionsItem::DebugScenario(scenario) => {
 6413                let context = actions_menu.actions.context;
 6414
 6415                workspace.update(cx, |workspace, cx| {
 6416                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6417                    workspace.start_debug_session(
 6418                        scenario,
 6419                        context,
 6420                        Some(buffer),
 6421                        None,
 6422                        window,
 6423                        cx,
 6424                    );
 6425                });
 6426                Some(Task::ready(Ok(())))
 6427            }
 6428        }
 6429    }
 6430
 6431    pub async fn open_project_transaction(
 6432        editor: &WeakEntity<Editor>,
 6433        workspace: WeakEntity<Workspace>,
 6434        transaction: ProjectTransaction,
 6435        title: String,
 6436        cx: &mut AsyncWindowContext,
 6437    ) -> Result<()> {
 6438        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6439        cx.update(|_, cx| {
 6440            entries.sort_unstable_by_key(|(buffer, _)| {
 6441                buffer.read(cx).file().map(|f| f.path().clone())
 6442            });
 6443        })?;
 6444        if entries.is_empty() {
 6445            return Ok(());
 6446        }
 6447
 6448        // If the project transaction's edits are all contained within this editor, then
 6449        // avoid opening a new editor to display them.
 6450
 6451        if let [(buffer, transaction)] = &*entries {
 6452            let excerpt = editor.update(cx, |editor, cx| {
 6453                editor
 6454                    .buffer()
 6455                    .read(cx)
 6456                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6457            })?;
 6458            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6459                && excerpted_buffer == *buffer
 6460            {
 6461                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6462                    let excerpt_range = excerpt_range.to_offset(buffer);
 6463                    buffer
 6464                        .edited_ranges_for_transaction::<usize>(transaction)
 6465                        .all(|range| {
 6466                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6467                        })
 6468                })?;
 6469
 6470                if all_edits_within_excerpt {
 6471                    return Ok(());
 6472                }
 6473            }
 6474        }
 6475
 6476        let mut ranges_to_highlight = Vec::new();
 6477        let excerpt_buffer = cx.new(|cx| {
 6478            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6479            for (buffer_handle, transaction) in &entries {
 6480                let edited_ranges = buffer_handle
 6481                    .read(cx)
 6482                    .edited_ranges_for_transaction::<Point>(transaction)
 6483                    .collect::<Vec<_>>();
 6484                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6485                    PathKey::for_buffer(buffer_handle, cx),
 6486                    buffer_handle.clone(),
 6487                    edited_ranges,
 6488                    multibuffer_context_lines(cx),
 6489                    cx,
 6490                );
 6491
 6492                ranges_to_highlight.extend(ranges);
 6493            }
 6494            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6495            multibuffer
 6496        })?;
 6497
 6498        workspace.update_in(cx, |workspace, window, cx| {
 6499            let project = workspace.project().clone();
 6500            let editor =
 6501                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6502            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6503            editor.update(cx, |editor, cx| {
 6504                editor.highlight_background::<Self>(
 6505                    &ranges_to_highlight,
 6506                    |theme| theme.colors().editor_highlighted_line_background,
 6507                    cx,
 6508                );
 6509            });
 6510        })?;
 6511
 6512        Ok(())
 6513    }
 6514
 6515    pub fn clear_code_action_providers(&mut self) {
 6516        self.code_action_providers.clear();
 6517        self.available_code_actions.take();
 6518    }
 6519
 6520    pub fn add_code_action_provider(
 6521        &mut self,
 6522        provider: Rc<dyn CodeActionProvider>,
 6523        window: &mut Window,
 6524        cx: &mut Context<Self>,
 6525    ) {
 6526        if self
 6527            .code_action_providers
 6528            .iter()
 6529            .any(|existing_provider| existing_provider.id() == provider.id())
 6530        {
 6531            return;
 6532        }
 6533
 6534        self.code_action_providers.push(provider);
 6535        self.refresh_code_actions(window, cx);
 6536    }
 6537
 6538    pub fn remove_code_action_provider(
 6539        &mut self,
 6540        id: Arc<str>,
 6541        window: &mut Window,
 6542        cx: &mut Context<Self>,
 6543    ) {
 6544        self.code_action_providers
 6545            .retain(|provider| provider.id() != id);
 6546        self.refresh_code_actions(window, cx);
 6547    }
 6548
 6549    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6550        !self.code_action_providers.is_empty()
 6551            && EditorSettings::get_global(cx).toolbar.code_actions
 6552    }
 6553
 6554    pub fn has_available_code_actions(&self) -> bool {
 6555        self.available_code_actions
 6556            .as_ref()
 6557            .is_some_and(|(_, actions)| !actions.is_empty())
 6558    }
 6559
 6560    fn render_inline_code_actions(
 6561        &self,
 6562        icon_size: ui::IconSize,
 6563        display_row: DisplayRow,
 6564        is_active: bool,
 6565        cx: &mut Context<Self>,
 6566    ) -> AnyElement {
 6567        let show_tooltip = !self.context_menu_visible();
 6568        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6569            .icon_size(icon_size)
 6570            .shape(ui::IconButtonShape::Square)
 6571            .icon_color(ui::Color::Hidden)
 6572            .toggle_state(is_active)
 6573            .when(show_tooltip, |this| {
 6574                this.tooltip({
 6575                    let focus_handle = self.focus_handle.clone();
 6576                    move |window, cx| {
 6577                        Tooltip::for_action_in(
 6578                            "Toggle Code Actions",
 6579                            &ToggleCodeActions {
 6580                                deployed_from: None,
 6581                                quick_launch: false,
 6582                            },
 6583                            &focus_handle,
 6584                            window,
 6585                            cx,
 6586                        )
 6587                    }
 6588                })
 6589            })
 6590            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6591                window.focus(&editor.focus_handle(cx));
 6592                editor.toggle_code_actions(
 6593                    &crate::actions::ToggleCodeActions {
 6594                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6595                            display_row,
 6596                        )),
 6597                        quick_launch: false,
 6598                    },
 6599                    window,
 6600                    cx,
 6601                );
 6602            }))
 6603            .into_any_element()
 6604    }
 6605
 6606    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6607        &self.context_menu
 6608    }
 6609
 6610    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6611        let newest_selection = self.selections.newest_anchor().clone();
 6612        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6613        let buffer = self.buffer.read(cx);
 6614        if newest_selection.head().diff_base_anchor.is_some() {
 6615            return None;
 6616        }
 6617        let (start_buffer, start) =
 6618            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6619        let (end_buffer, end) =
 6620            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6621        if start_buffer != end_buffer {
 6622            return None;
 6623        }
 6624
 6625        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6626            cx.background_executor()
 6627                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6628                .await;
 6629
 6630            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6631                let providers = this.code_action_providers.clone();
 6632                let tasks = this
 6633                    .code_action_providers
 6634                    .iter()
 6635                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6636                    .collect::<Vec<_>>();
 6637                (providers, tasks)
 6638            })?;
 6639
 6640            let mut actions = Vec::new();
 6641            for (provider, provider_actions) in
 6642                providers.into_iter().zip(future::join_all(tasks).await)
 6643            {
 6644                if let Some(provider_actions) = provider_actions.log_err() {
 6645                    actions.extend(provider_actions.into_iter().map(|action| {
 6646                        AvailableCodeAction {
 6647                            excerpt_id: newest_selection.start.excerpt_id,
 6648                            action,
 6649                            provider: provider.clone(),
 6650                        }
 6651                    }));
 6652                }
 6653            }
 6654
 6655            this.update(cx, |this, cx| {
 6656                this.available_code_actions = if actions.is_empty() {
 6657                    None
 6658                } else {
 6659                    Some((
 6660                        Location {
 6661                            buffer: start_buffer,
 6662                            range: start..end,
 6663                        },
 6664                        actions.into(),
 6665                    ))
 6666                };
 6667                cx.notify();
 6668            })
 6669        }));
 6670        None
 6671    }
 6672
 6673    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6674        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6675            self.show_git_blame_inline = false;
 6676
 6677            self.show_git_blame_inline_delay_task =
 6678                Some(cx.spawn_in(window, async move |this, cx| {
 6679                    cx.background_executor().timer(delay).await;
 6680
 6681                    this.update(cx, |this, cx| {
 6682                        this.show_git_blame_inline = true;
 6683                        cx.notify();
 6684                    })
 6685                    .log_err();
 6686                }));
 6687        }
 6688    }
 6689
 6690    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6691        let snapshot = self.snapshot(window, cx);
 6692        let cursor = self.selections.newest::<Point>(cx).head();
 6693        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6694        else {
 6695            return;
 6696        };
 6697
 6698        let Some(blame) = self.blame.as_ref() else {
 6699            return;
 6700        };
 6701
 6702        let row_info = RowInfo {
 6703            buffer_id: Some(buffer.remote_id()),
 6704            buffer_row: Some(point.row),
 6705            ..Default::default()
 6706        };
 6707        let Some((buffer, blame_entry)) = blame
 6708            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6709            .flatten()
 6710        else {
 6711            return;
 6712        };
 6713
 6714        let anchor = self.selections.newest_anchor().head();
 6715        let position = self.to_pixel_point(anchor, &snapshot, window);
 6716        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6717            self.show_blame_popover(
 6718                buffer,
 6719                &blame_entry,
 6720                position + last_bounds.origin,
 6721                true,
 6722                cx,
 6723            );
 6724        };
 6725    }
 6726
 6727    fn show_blame_popover(
 6728        &mut self,
 6729        buffer: BufferId,
 6730        blame_entry: &BlameEntry,
 6731        position: gpui::Point<Pixels>,
 6732        ignore_timeout: bool,
 6733        cx: &mut Context<Self>,
 6734    ) {
 6735        if let Some(state) = &mut self.inline_blame_popover {
 6736            state.hide_task.take();
 6737        } else {
 6738            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6739            let blame_entry = blame_entry.clone();
 6740            let show_task = cx.spawn(async move |editor, cx| {
 6741                if !ignore_timeout {
 6742                    cx.background_executor()
 6743                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6744                        .await;
 6745                }
 6746                editor
 6747                    .update(cx, |editor, cx| {
 6748                        editor.inline_blame_popover_show_task.take();
 6749                        let Some(blame) = editor.blame.as_ref() else {
 6750                            return;
 6751                        };
 6752                        let blame = blame.read(cx);
 6753                        let details = blame.details_for_entry(buffer, &blame_entry);
 6754                        let markdown = cx.new(|cx| {
 6755                            Markdown::new(
 6756                                details
 6757                                    .as_ref()
 6758                                    .map(|message| message.message.clone())
 6759                                    .unwrap_or_default(),
 6760                                None,
 6761                                None,
 6762                                cx,
 6763                            )
 6764                        });
 6765                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6766                            position,
 6767                            hide_task: None,
 6768                            popover_bounds: None,
 6769                            popover_state: InlineBlamePopoverState {
 6770                                scroll_handle: ScrollHandle::new(),
 6771                                commit_message: details,
 6772                                markdown,
 6773                            },
 6774                            keyboard_grace: ignore_timeout,
 6775                        });
 6776                        cx.notify();
 6777                    })
 6778                    .ok();
 6779            });
 6780            self.inline_blame_popover_show_task = Some(show_task);
 6781        }
 6782    }
 6783
 6784    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6785        self.inline_blame_popover_show_task.take();
 6786        if let Some(state) = &mut self.inline_blame_popover {
 6787            let hide_task = cx.spawn(async move |editor, cx| {
 6788                cx.background_executor()
 6789                    .timer(std::time::Duration::from_millis(100))
 6790                    .await;
 6791                editor
 6792                    .update(cx, |editor, cx| {
 6793                        editor.inline_blame_popover.take();
 6794                        cx.notify();
 6795                    })
 6796                    .ok();
 6797            });
 6798            state.hide_task = Some(hide_task);
 6799        }
 6800    }
 6801
 6802    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6803        if self.pending_rename.is_some() {
 6804            return None;
 6805        }
 6806
 6807        let provider = self.semantics_provider.clone()?;
 6808        let buffer = self.buffer.read(cx);
 6809        let newest_selection = self.selections.newest_anchor().clone();
 6810        let cursor_position = newest_selection.head();
 6811        let (cursor_buffer, cursor_buffer_position) =
 6812            buffer.text_anchor_for_position(cursor_position, cx)?;
 6813        let (tail_buffer, tail_buffer_position) =
 6814            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6815        if cursor_buffer != tail_buffer {
 6816            return None;
 6817        }
 6818
 6819        let snapshot = cursor_buffer.read(cx).snapshot();
 6820        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6821        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6822        if start_word_range != end_word_range {
 6823            self.document_highlights_task.take();
 6824            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6825            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6826            return None;
 6827        }
 6828
 6829        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6830        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6831            cx.background_executor()
 6832                .timer(Duration::from_millis(debounce))
 6833                .await;
 6834
 6835            let highlights = if let Some(highlights) = cx
 6836                .update(|cx| {
 6837                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6838                })
 6839                .ok()
 6840                .flatten()
 6841            {
 6842                highlights.await.log_err()
 6843            } else {
 6844                None
 6845            };
 6846
 6847            if let Some(highlights) = highlights {
 6848                this.update(cx, |this, cx| {
 6849                    if this.pending_rename.is_some() {
 6850                        return;
 6851                    }
 6852
 6853                    let buffer = this.buffer.read(cx);
 6854                    if buffer
 6855                        .text_anchor_for_position(cursor_position, cx)
 6856                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6857                    {
 6858                        return;
 6859                    }
 6860
 6861                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6862                    let mut write_ranges = Vec::new();
 6863                    let mut read_ranges = Vec::new();
 6864                    for highlight in highlights {
 6865                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6866                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6867                        {
 6868                            let start = highlight
 6869                                .range
 6870                                .start
 6871                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6872                            let end = highlight
 6873                                .range
 6874                                .end
 6875                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6876                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6877                                continue;
 6878                            }
 6879
 6880                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6881                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6882                                write_ranges.push(range);
 6883                            } else {
 6884                                read_ranges.push(range);
 6885                            }
 6886                        }
 6887                    }
 6888
 6889                    this.highlight_background::<DocumentHighlightRead>(
 6890                        &read_ranges,
 6891                        |theme| theme.colors().editor_document_highlight_read_background,
 6892                        cx,
 6893                    );
 6894                    this.highlight_background::<DocumentHighlightWrite>(
 6895                        &write_ranges,
 6896                        |theme| theme.colors().editor_document_highlight_write_background,
 6897                        cx,
 6898                    );
 6899                    cx.notify();
 6900                })
 6901                .log_err();
 6902            }
 6903        }));
 6904        None
 6905    }
 6906
 6907    fn prepare_highlight_query_from_selection(
 6908        &mut self,
 6909        cx: &mut Context<Editor>,
 6910    ) -> Option<(String, Range<Anchor>)> {
 6911        if matches!(self.mode, EditorMode::SingleLine) {
 6912            return None;
 6913        }
 6914        if !EditorSettings::get_global(cx).selection_highlight {
 6915            return None;
 6916        }
 6917        if self.selections.count() != 1 || self.selections.line_mode() {
 6918            return None;
 6919        }
 6920        let selection = self.selections.newest::<Point>(cx);
 6921        if selection.is_empty() || selection.start.row != selection.end.row {
 6922            return None;
 6923        }
 6924        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6925        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6926        let query = multi_buffer_snapshot
 6927            .text_for_range(selection_anchor_range.clone())
 6928            .collect::<String>();
 6929        if query.trim().is_empty() {
 6930            return None;
 6931        }
 6932        Some((query, selection_anchor_range))
 6933    }
 6934
 6935    fn update_selection_occurrence_highlights(
 6936        &mut self,
 6937        query_text: String,
 6938        query_range: Range<Anchor>,
 6939        multi_buffer_range_to_query: Range<Point>,
 6940        use_debounce: bool,
 6941        window: &mut Window,
 6942        cx: &mut Context<Editor>,
 6943    ) -> Task<()> {
 6944        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6945        cx.spawn_in(window, async move |editor, cx| {
 6946            if use_debounce {
 6947                cx.background_executor()
 6948                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6949                    .await;
 6950            }
 6951            let match_task = cx.background_spawn(async move {
 6952                let buffer_ranges = multi_buffer_snapshot
 6953                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6954                    .into_iter()
 6955                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6956                let mut match_ranges = Vec::new();
 6957                let Ok(regex) = project::search::SearchQuery::text(
 6958                    query_text.clone(),
 6959                    false,
 6960                    false,
 6961                    false,
 6962                    Default::default(),
 6963                    Default::default(),
 6964                    false,
 6965                    None,
 6966                ) else {
 6967                    return Vec::default();
 6968                };
 6969                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6970                    match_ranges.extend(
 6971                        regex
 6972                            .search(buffer_snapshot, Some(search_range.clone()))
 6973                            .await
 6974                            .into_iter()
 6975                            .filter_map(|match_range| {
 6976                                let match_start = buffer_snapshot
 6977                                    .anchor_after(search_range.start + match_range.start);
 6978                                let match_end = buffer_snapshot
 6979                                    .anchor_before(search_range.start + match_range.end);
 6980                                let match_anchor_range = Anchor::range_in_buffer(
 6981                                    excerpt_id,
 6982                                    buffer_snapshot.remote_id(),
 6983                                    match_start..match_end,
 6984                                );
 6985                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6986                            }),
 6987                    );
 6988                }
 6989                match_ranges
 6990            });
 6991            let match_ranges = match_task.await;
 6992            editor
 6993                .update_in(cx, |editor, _, cx| {
 6994                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6995                    if !match_ranges.is_empty() {
 6996                        editor.highlight_background::<SelectedTextHighlight>(
 6997                            &match_ranges,
 6998                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6999                            cx,
 7000                        )
 7001                    }
 7002                })
 7003                .log_err();
 7004        })
 7005    }
 7006
 7007    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7008        struct NewlineFold;
 7009        let type_id = std::any::TypeId::of::<NewlineFold>();
 7010        if !self.mode.is_single_line() {
 7011            return;
 7012        }
 7013        let snapshot = self.snapshot(window, cx);
 7014        if snapshot.buffer_snapshot().max_point().row == 0 {
 7015            return;
 7016        }
 7017        let task = cx.background_spawn(async move {
 7018            let new_newlines = snapshot
 7019                .buffer_chars_at(0)
 7020                .filter_map(|(c, i)| {
 7021                    if c == '\n' {
 7022                        Some(
 7023                            snapshot.buffer_snapshot().anchor_after(i)
 7024                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7025                        )
 7026                    } else {
 7027                        None
 7028                    }
 7029                })
 7030                .collect::<Vec<_>>();
 7031            let existing_newlines = snapshot
 7032                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7033                .filter_map(|fold| {
 7034                    if fold.placeholder.type_tag == Some(type_id) {
 7035                        Some(fold.range.start..fold.range.end)
 7036                    } else {
 7037                        None
 7038                    }
 7039                })
 7040                .collect::<Vec<_>>();
 7041
 7042            (new_newlines, existing_newlines)
 7043        });
 7044        self.folding_newlines = cx.spawn(async move |this, cx| {
 7045            let (new_newlines, existing_newlines) = task.await;
 7046            if new_newlines == existing_newlines {
 7047                return;
 7048            }
 7049            let placeholder = FoldPlaceholder {
 7050                render: Arc::new(move |_, _, cx| {
 7051                    div()
 7052                        .bg(cx.theme().status().hint_background)
 7053                        .border_b_1()
 7054                        .size_full()
 7055                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7056                        .border_color(cx.theme().status().hint)
 7057                        .child("\\n")
 7058                        .into_any()
 7059                }),
 7060                constrain_width: false,
 7061                merge_adjacent: false,
 7062                type_tag: Some(type_id),
 7063            };
 7064            let creases = new_newlines
 7065                .into_iter()
 7066                .map(|range| Crease::simple(range, placeholder.clone()))
 7067                .collect();
 7068            this.update(cx, |this, cx| {
 7069                this.display_map.update(cx, |display_map, cx| {
 7070                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7071                    display_map.fold(creases, cx);
 7072                });
 7073            })
 7074            .ok();
 7075        });
 7076    }
 7077
 7078    fn refresh_selected_text_highlights(
 7079        &mut self,
 7080        on_buffer_edit: bool,
 7081        window: &mut Window,
 7082        cx: &mut Context<Editor>,
 7083    ) {
 7084        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7085        else {
 7086            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7087            self.quick_selection_highlight_task.take();
 7088            self.debounced_selection_highlight_task.take();
 7089            return;
 7090        };
 7091        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7092        if on_buffer_edit
 7093            || self
 7094                .quick_selection_highlight_task
 7095                .as_ref()
 7096                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7097        {
 7098            let multi_buffer_visible_start = self
 7099                .scroll_manager
 7100                .anchor()
 7101                .anchor
 7102                .to_point(&multi_buffer_snapshot);
 7103            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7104                multi_buffer_visible_start
 7105                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7106                Bias::Left,
 7107            );
 7108            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7109            self.quick_selection_highlight_task = Some((
 7110                query_range.clone(),
 7111                self.update_selection_occurrence_highlights(
 7112                    query_text.clone(),
 7113                    query_range.clone(),
 7114                    multi_buffer_visible_range,
 7115                    false,
 7116                    window,
 7117                    cx,
 7118                ),
 7119            ));
 7120        }
 7121        if on_buffer_edit
 7122            || self
 7123                .debounced_selection_highlight_task
 7124                .as_ref()
 7125                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7126        {
 7127            let multi_buffer_start = multi_buffer_snapshot
 7128                .anchor_before(0)
 7129                .to_point(&multi_buffer_snapshot);
 7130            let multi_buffer_end = multi_buffer_snapshot
 7131                .anchor_after(multi_buffer_snapshot.len())
 7132                .to_point(&multi_buffer_snapshot);
 7133            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7134            self.debounced_selection_highlight_task = Some((
 7135                query_range.clone(),
 7136                self.update_selection_occurrence_highlights(
 7137                    query_text,
 7138                    query_range,
 7139                    multi_buffer_full_range,
 7140                    true,
 7141                    window,
 7142                    cx,
 7143                ),
 7144            ));
 7145        }
 7146    }
 7147
 7148    pub fn refresh_edit_prediction(
 7149        &mut self,
 7150        debounce: bool,
 7151        user_requested: bool,
 7152        window: &mut Window,
 7153        cx: &mut Context<Self>,
 7154    ) -> Option<()> {
 7155        if DisableAiSettings::get_global(cx).disable_ai {
 7156            return None;
 7157        }
 7158
 7159        let provider = self.edit_prediction_provider()?;
 7160        let cursor = self.selections.newest_anchor().head();
 7161        let (buffer, cursor_buffer_position) =
 7162            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7163
 7164        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7165            self.discard_edit_prediction(false, cx);
 7166            return None;
 7167        }
 7168
 7169        self.update_visible_edit_prediction(window, cx);
 7170
 7171        if !user_requested
 7172            && (!self.should_show_edit_predictions()
 7173                || !self.is_focused(window)
 7174                || buffer.read(cx).is_empty())
 7175        {
 7176            self.discard_edit_prediction(false, cx);
 7177            return None;
 7178        }
 7179
 7180        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7181        Some(())
 7182    }
 7183
 7184    fn show_edit_predictions_in_menu(&self) -> bool {
 7185        match self.edit_prediction_settings {
 7186            EditPredictionSettings::Disabled => false,
 7187            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7188        }
 7189    }
 7190
 7191    pub fn edit_predictions_enabled(&self) -> bool {
 7192        match self.edit_prediction_settings {
 7193            EditPredictionSettings::Disabled => false,
 7194            EditPredictionSettings::Enabled { .. } => true,
 7195        }
 7196    }
 7197
 7198    fn edit_prediction_requires_modifier(&self) -> bool {
 7199        match self.edit_prediction_settings {
 7200            EditPredictionSettings::Disabled => false,
 7201            EditPredictionSettings::Enabled {
 7202                preview_requires_modifier,
 7203                ..
 7204            } => preview_requires_modifier,
 7205        }
 7206    }
 7207
 7208    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7209        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7210            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7211            self.discard_edit_prediction(false, cx);
 7212        } else {
 7213            let selection = self.selections.newest_anchor();
 7214            let cursor = selection.head();
 7215
 7216            if let Some((buffer, cursor_buffer_position)) =
 7217                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7218            {
 7219                self.edit_prediction_settings =
 7220                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7221            }
 7222        }
 7223    }
 7224
 7225    fn edit_prediction_settings_at_position(
 7226        &self,
 7227        buffer: &Entity<Buffer>,
 7228        buffer_position: language::Anchor,
 7229        cx: &App,
 7230    ) -> EditPredictionSettings {
 7231        if !self.mode.is_full()
 7232            || !self.show_edit_predictions_override.unwrap_or(true)
 7233            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7234        {
 7235            return EditPredictionSettings::Disabled;
 7236        }
 7237
 7238        let buffer = buffer.read(cx);
 7239
 7240        let file = buffer.file();
 7241
 7242        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7243            return EditPredictionSettings::Disabled;
 7244        };
 7245
 7246        let by_provider = matches!(
 7247            self.menu_edit_predictions_policy,
 7248            MenuEditPredictionsPolicy::ByProvider
 7249        );
 7250
 7251        let show_in_menu = by_provider
 7252            && self
 7253                .edit_prediction_provider
 7254                .as_ref()
 7255                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7256
 7257        let preview_requires_modifier =
 7258            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7259
 7260        EditPredictionSettings::Enabled {
 7261            show_in_menu,
 7262            preview_requires_modifier,
 7263        }
 7264    }
 7265
 7266    fn should_show_edit_predictions(&self) -> bool {
 7267        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7268    }
 7269
 7270    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7271        matches!(
 7272            self.edit_prediction_preview,
 7273            EditPredictionPreview::Active { .. }
 7274        )
 7275    }
 7276
 7277    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7278        let cursor = self.selections.newest_anchor().head();
 7279        if let Some((buffer, cursor_position)) =
 7280            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7281        {
 7282            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7283        } else {
 7284            false
 7285        }
 7286    }
 7287
 7288    pub fn supports_minimap(&self, cx: &App) -> bool {
 7289        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7290    }
 7291
 7292    fn edit_predictions_enabled_in_buffer(
 7293        &self,
 7294        buffer: &Entity<Buffer>,
 7295        buffer_position: language::Anchor,
 7296        cx: &App,
 7297    ) -> bool {
 7298        maybe!({
 7299            if self.read_only(cx) {
 7300                return Some(false);
 7301            }
 7302            let provider = self.edit_prediction_provider()?;
 7303            if !provider.is_enabled(buffer, buffer_position, cx) {
 7304                return Some(false);
 7305            }
 7306            let buffer = buffer.read(cx);
 7307            let Some(file) = buffer.file() else {
 7308                return Some(true);
 7309            };
 7310            let settings = all_language_settings(Some(file), cx);
 7311            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7312        })
 7313        .unwrap_or(false)
 7314    }
 7315
 7316    fn cycle_edit_prediction(
 7317        &mut self,
 7318        direction: Direction,
 7319        window: &mut Window,
 7320        cx: &mut Context<Self>,
 7321    ) -> Option<()> {
 7322        let provider = self.edit_prediction_provider()?;
 7323        let cursor = self.selections.newest_anchor().head();
 7324        let (buffer, cursor_buffer_position) =
 7325            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7326        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7327            return None;
 7328        }
 7329
 7330        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7331        self.update_visible_edit_prediction(window, cx);
 7332
 7333        Some(())
 7334    }
 7335
 7336    pub fn show_edit_prediction(
 7337        &mut self,
 7338        _: &ShowEditPrediction,
 7339        window: &mut Window,
 7340        cx: &mut Context<Self>,
 7341    ) {
 7342        if !self.has_active_edit_prediction() {
 7343            self.refresh_edit_prediction(false, true, window, cx);
 7344            return;
 7345        }
 7346
 7347        self.update_visible_edit_prediction(window, cx);
 7348    }
 7349
 7350    pub fn display_cursor_names(
 7351        &mut self,
 7352        _: &DisplayCursorNames,
 7353        window: &mut Window,
 7354        cx: &mut Context<Self>,
 7355    ) {
 7356        self.show_cursor_names(window, cx);
 7357    }
 7358
 7359    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7360        self.show_cursor_names = true;
 7361        cx.notify();
 7362        cx.spawn_in(window, async move |this, cx| {
 7363            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7364            this.update(cx, |this, cx| {
 7365                this.show_cursor_names = false;
 7366                cx.notify()
 7367            })
 7368            .ok()
 7369        })
 7370        .detach();
 7371    }
 7372
 7373    pub fn next_edit_prediction(
 7374        &mut self,
 7375        _: &NextEditPrediction,
 7376        window: &mut Window,
 7377        cx: &mut Context<Self>,
 7378    ) {
 7379        if self.has_active_edit_prediction() {
 7380            self.cycle_edit_prediction(Direction::Next, window, cx);
 7381        } else {
 7382            let is_copilot_disabled = self
 7383                .refresh_edit_prediction(false, true, window, cx)
 7384                .is_none();
 7385            if is_copilot_disabled {
 7386                cx.propagate();
 7387            }
 7388        }
 7389    }
 7390
 7391    pub fn previous_edit_prediction(
 7392        &mut self,
 7393        _: &PreviousEditPrediction,
 7394        window: &mut Window,
 7395        cx: &mut Context<Self>,
 7396    ) {
 7397        if self.has_active_edit_prediction() {
 7398            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7399        } else {
 7400            let is_copilot_disabled = self
 7401                .refresh_edit_prediction(false, true, window, cx)
 7402                .is_none();
 7403            if is_copilot_disabled {
 7404                cx.propagate();
 7405            }
 7406        }
 7407    }
 7408
 7409    pub fn accept_edit_prediction(
 7410        &mut self,
 7411        _: &AcceptEditPrediction,
 7412        window: &mut Window,
 7413        cx: &mut Context<Self>,
 7414    ) {
 7415        if self.show_edit_predictions_in_menu() {
 7416            self.hide_context_menu(window, cx);
 7417        }
 7418
 7419        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7420            return;
 7421        };
 7422
 7423        match &active_edit_prediction.completion {
 7424            EditPrediction::MoveWithin { target, .. } => {
 7425                let target = *target;
 7426
 7427                if let Some(position_map) = &self.last_position_map {
 7428                    if position_map
 7429                        .visible_row_range
 7430                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7431                        || !self.edit_prediction_requires_modifier()
 7432                    {
 7433                        self.unfold_ranges(&[target..target], true, false, cx);
 7434                        // Note that this is also done in vim's handler of the Tab action.
 7435                        self.change_selections(
 7436                            SelectionEffects::scroll(Autoscroll::newest()),
 7437                            window,
 7438                            cx,
 7439                            |selections| {
 7440                                selections.select_anchor_ranges([target..target]);
 7441                            },
 7442                        );
 7443                        self.clear_row_highlights::<EditPredictionPreview>();
 7444
 7445                        self.edit_prediction_preview
 7446                            .set_previous_scroll_position(None);
 7447                    } else {
 7448                        self.edit_prediction_preview
 7449                            .set_previous_scroll_position(Some(
 7450                                position_map.snapshot.scroll_anchor,
 7451                            ));
 7452
 7453                        self.highlight_rows::<EditPredictionPreview>(
 7454                            target..target,
 7455                            cx.theme().colors().editor_highlighted_line_background,
 7456                            RowHighlightOptions {
 7457                                autoscroll: true,
 7458                                ..Default::default()
 7459                            },
 7460                            cx,
 7461                        );
 7462                        self.request_autoscroll(Autoscroll::fit(), cx);
 7463                    }
 7464                }
 7465            }
 7466            EditPrediction::MoveOutside { snapshot, target } => {
 7467                if let Some(workspace) = self.workspace() {
 7468                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7469                        .detach_and_log_err(cx);
 7470                }
 7471            }
 7472            EditPrediction::Edit { edits, .. } => {
 7473                self.report_edit_prediction_event(
 7474                    active_edit_prediction.completion_id.clone(),
 7475                    true,
 7476                    cx,
 7477                );
 7478
 7479                if let Some(provider) = self.edit_prediction_provider() {
 7480                    provider.accept(cx);
 7481                }
 7482
 7483                // Store the transaction ID and selections before applying the edit
 7484                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7485
 7486                let snapshot = self.buffer.read(cx).snapshot(cx);
 7487                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7488
 7489                self.buffer.update(cx, |buffer, cx| {
 7490                    buffer.edit(edits.iter().cloned(), None, cx)
 7491                });
 7492
 7493                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7494                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7495                });
 7496
 7497                let selections = self.selections.disjoint_anchors_arc();
 7498                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7499                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7500                    if has_new_transaction {
 7501                        self.selection_history
 7502                            .insert_transaction(transaction_id_now, selections);
 7503                    }
 7504                }
 7505
 7506                self.update_visible_edit_prediction(window, cx);
 7507                if self.active_edit_prediction.is_none() {
 7508                    self.refresh_edit_prediction(true, true, window, cx);
 7509                }
 7510
 7511                cx.notify();
 7512            }
 7513        }
 7514
 7515        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7516    }
 7517
 7518    pub fn accept_partial_edit_prediction(
 7519        &mut self,
 7520        _: &AcceptPartialEditPrediction,
 7521        window: &mut Window,
 7522        cx: &mut Context<Self>,
 7523    ) {
 7524        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7525            return;
 7526        };
 7527        if self.selections.count() != 1 {
 7528            return;
 7529        }
 7530
 7531        match &active_edit_prediction.completion {
 7532            EditPrediction::MoveWithin { target, .. } => {
 7533                let target = *target;
 7534                self.change_selections(
 7535                    SelectionEffects::scroll(Autoscroll::newest()),
 7536                    window,
 7537                    cx,
 7538                    |selections| {
 7539                        selections.select_anchor_ranges([target..target]);
 7540                    },
 7541                );
 7542            }
 7543            EditPrediction::MoveOutside { snapshot, target } => {
 7544                if let Some(workspace) = self.workspace() {
 7545                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7546                        .detach_and_log_err(cx);
 7547                }
 7548            }
 7549            EditPrediction::Edit { edits, .. } => {
 7550                self.report_edit_prediction_event(
 7551                    active_edit_prediction.completion_id.clone(),
 7552                    true,
 7553                    cx,
 7554                );
 7555
 7556                // Find an insertion that starts at the cursor position.
 7557                let snapshot = self.buffer.read(cx).snapshot(cx);
 7558                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7559                let insertion = edits.iter().find_map(|(range, text)| {
 7560                    let range = range.to_offset(&snapshot);
 7561                    if range.is_empty() && range.start == cursor_offset {
 7562                        Some(text)
 7563                    } else {
 7564                        None
 7565                    }
 7566                });
 7567
 7568                if let Some(text) = insertion {
 7569                    let mut partial_completion = text
 7570                        .chars()
 7571                        .by_ref()
 7572                        .take_while(|c| c.is_alphabetic())
 7573                        .collect::<String>();
 7574                    if partial_completion.is_empty() {
 7575                        partial_completion = text
 7576                            .chars()
 7577                            .by_ref()
 7578                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7579                            .collect::<String>();
 7580                    }
 7581
 7582                    cx.emit(EditorEvent::InputHandled {
 7583                        utf16_range_to_replace: None,
 7584                        text: partial_completion.clone().into(),
 7585                    });
 7586
 7587                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7588
 7589                    self.refresh_edit_prediction(true, true, window, cx);
 7590                    cx.notify();
 7591                } else {
 7592                    self.accept_edit_prediction(&Default::default(), window, cx);
 7593                }
 7594            }
 7595        }
 7596    }
 7597
 7598    fn discard_edit_prediction(
 7599        &mut self,
 7600        should_report_edit_prediction_event: bool,
 7601        cx: &mut Context<Self>,
 7602    ) -> bool {
 7603        if should_report_edit_prediction_event {
 7604            let completion_id = self
 7605                .active_edit_prediction
 7606                .as_ref()
 7607                .and_then(|active_completion| active_completion.completion_id.clone());
 7608
 7609            self.report_edit_prediction_event(completion_id, false, cx);
 7610        }
 7611
 7612        if let Some(provider) = self.edit_prediction_provider() {
 7613            provider.discard(cx);
 7614        }
 7615
 7616        self.take_active_edit_prediction(cx)
 7617    }
 7618
 7619    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7620        let Some(provider) = self.edit_prediction_provider() else {
 7621            return;
 7622        };
 7623
 7624        let Some((_, buffer, _)) = self
 7625            .buffer
 7626            .read(cx)
 7627            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7628        else {
 7629            return;
 7630        };
 7631
 7632        let extension = buffer
 7633            .read(cx)
 7634            .file()
 7635            .and_then(|file| Some(file.path().extension()?.to_string()));
 7636
 7637        let event_type = match accepted {
 7638            true => "Edit Prediction Accepted",
 7639            false => "Edit Prediction Discarded",
 7640        };
 7641        telemetry::event!(
 7642            event_type,
 7643            provider = provider.name(),
 7644            prediction_id = id,
 7645            suggestion_accepted = accepted,
 7646            file_extension = extension,
 7647        );
 7648    }
 7649
 7650    fn open_editor_at_anchor(
 7651        snapshot: &language::BufferSnapshot,
 7652        target: language::Anchor,
 7653        workspace: &Entity<Workspace>,
 7654        window: &mut Window,
 7655        cx: &mut App,
 7656    ) -> Task<Result<()>> {
 7657        workspace.update(cx, |workspace, cx| {
 7658            let path = snapshot.file().map(|file| file.full_path(cx));
 7659            let Some(path) =
 7660                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7661            else {
 7662                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7663            };
 7664            let target = text::ToPoint::to_point(&target, snapshot);
 7665            let item = workspace.open_path(path, None, true, window, cx);
 7666            window.spawn(cx, async move |cx| {
 7667                let Some(editor) = item.await?.downcast::<Editor>() else {
 7668                    return Ok(());
 7669                };
 7670                editor
 7671                    .update_in(cx, |editor, window, cx| {
 7672                        editor.go_to_singleton_buffer_point(target, window, cx);
 7673                    })
 7674                    .ok();
 7675                anyhow::Ok(())
 7676            })
 7677        })
 7678    }
 7679
 7680    pub fn has_active_edit_prediction(&self) -> bool {
 7681        self.active_edit_prediction.is_some()
 7682    }
 7683
 7684    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7685        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7686            return false;
 7687        };
 7688
 7689        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7690        self.clear_highlights::<EditPredictionHighlight>(cx);
 7691        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7692        true
 7693    }
 7694
 7695    /// Returns true when we're displaying the edit prediction popover below the cursor
 7696    /// like we are not previewing and the LSP autocomplete menu is visible
 7697    /// or we are in `when_holding_modifier` mode.
 7698    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7699        if self.edit_prediction_preview_is_active()
 7700            || !self.show_edit_predictions_in_menu()
 7701            || !self.edit_predictions_enabled()
 7702        {
 7703            return false;
 7704        }
 7705
 7706        if self.has_visible_completions_menu() {
 7707            return true;
 7708        }
 7709
 7710        has_completion && self.edit_prediction_requires_modifier()
 7711    }
 7712
 7713    fn handle_modifiers_changed(
 7714        &mut self,
 7715        modifiers: Modifiers,
 7716        position_map: &PositionMap,
 7717        window: &mut Window,
 7718        cx: &mut Context<Self>,
 7719    ) {
 7720        if self.show_edit_predictions_in_menu() {
 7721            self.update_edit_prediction_preview(&modifiers, window, cx);
 7722        }
 7723
 7724        self.update_selection_mode(&modifiers, position_map, window, cx);
 7725
 7726        let mouse_position = window.mouse_position();
 7727        if !position_map.text_hitbox.is_hovered(window) {
 7728            return;
 7729        }
 7730
 7731        self.update_hovered_link(
 7732            position_map.point_for_position(mouse_position),
 7733            &position_map.snapshot,
 7734            modifiers,
 7735            window,
 7736            cx,
 7737        )
 7738    }
 7739
 7740    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7741        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7742        if invert {
 7743            match multi_cursor_setting {
 7744                MultiCursorModifier::Alt => modifiers.alt,
 7745                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7746            }
 7747        } else {
 7748            match multi_cursor_setting {
 7749                MultiCursorModifier::Alt => modifiers.secondary(),
 7750                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7751            }
 7752        }
 7753    }
 7754
 7755    fn columnar_selection_mode(
 7756        modifiers: &Modifiers,
 7757        cx: &mut Context<Self>,
 7758    ) -> Option<ColumnarMode> {
 7759        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7760            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7761                Some(ColumnarMode::FromMouse)
 7762            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7763                Some(ColumnarMode::FromSelection)
 7764            } else {
 7765                None
 7766            }
 7767        } else {
 7768            None
 7769        }
 7770    }
 7771
 7772    fn update_selection_mode(
 7773        &mut self,
 7774        modifiers: &Modifiers,
 7775        position_map: &PositionMap,
 7776        window: &mut Window,
 7777        cx: &mut Context<Self>,
 7778    ) {
 7779        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7780            return;
 7781        };
 7782        if self.selections.pending_anchor().is_none() {
 7783            return;
 7784        }
 7785
 7786        let mouse_position = window.mouse_position();
 7787        let point_for_position = position_map.point_for_position(mouse_position);
 7788        let position = point_for_position.previous_valid;
 7789
 7790        self.select(
 7791            SelectPhase::BeginColumnar {
 7792                position,
 7793                reset: false,
 7794                mode,
 7795                goal_column: point_for_position.exact_unclipped.column(),
 7796            },
 7797            window,
 7798            cx,
 7799        );
 7800    }
 7801
 7802    fn update_edit_prediction_preview(
 7803        &mut self,
 7804        modifiers: &Modifiers,
 7805        window: &mut Window,
 7806        cx: &mut Context<Self>,
 7807    ) {
 7808        let mut modifiers_held = false;
 7809        if let Some(accept_keystroke) = self
 7810            .accept_edit_prediction_keybind(false, window, cx)
 7811            .keystroke()
 7812        {
 7813            modifiers_held = modifiers_held
 7814                || (accept_keystroke.modifiers() == modifiers
 7815                    && accept_keystroke.modifiers().modified());
 7816        };
 7817        if let Some(accept_partial_keystroke) = self
 7818            .accept_edit_prediction_keybind(true, window, cx)
 7819            .keystroke()
 7820        {
 7821            modifiers_held = modifiers_held
 7822                || (accept_partial_keystroke.modifiers() == modifiers
 7823                    && accept_partial_keystroke.modifiers().modified());
 7824        }
 7825
 7826        if modifiers_held {
 7827            if matches!(
 7828                self.edit_prediction_preview,
 7829                EditPredictionPreview::Inactive { .. }
 7830            ) {
 7831                self.edit_prediction_preview = EditPredictionPreview::Active {
 7832                    previous_scroll_position: None,
 7833                    since: Instant::now(),
 7834                };
 7835
 7836                self.update_visible_edit_prediction(window, cx);
 7837                cx.notify();
 7838            }
 7839        } else if let EditPredictionPreview::Active {
 7840            previous_scroll_position,
 7841            since,
 7842        } = self.edit_prediction_preview
 7843        {
 7844            if let (Some(previous_scroll_position), Some(position_map)) =
 7845                (previous_scroll_position, self.last_position_map.as_ref())
 7846            {
 7847                self.set_scroll_position(
 7848                    previous_scroll_position
 7849                        .scroll_position(&position_map.snapshot.display_snapshot),
 7850                    window,
 7851                    cx,
 7852                );
 7853            }
 7854
 7855            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7856                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7857            };
 7858            self.clear_row_highlights::<EditPredictionPreview>();
 7859            self.update_visible_edit_prediction(window, cx);
 7860            cx.notify();
 7861        }
 7862    }
 7863
 7864    fn update_visible_edit_prediction(
 7865        &mut self,
 7866        _window: &mut Window,
 7867        cx: &mut Context<Self>,
 7868    ) -> Option<()> {
 7869        if DisableAiSettings::get_global(cx).disable_ai {
 7870            return None;
 7871        }
 7872
 7873        if self.ime_transaction.is_some() {
 7874            self.discard_edit_prediction(false, cx);
 7875            return None;
 7876        }
 7877
 7878        let selection = self.selections.newest_anchor();
 7879        let cursor = selection.head();
 7880        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7881        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7882        let excerpt_id = cursor.excerpt_id;
 7883
 7884        let show_in_menu = self.show_edit_predictions_in_menu();
 7885        let completions_menu_has_precedence = !show_in_menu
 7886            && (self.context_menu.borrow().is_some()
 7887                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7888
 7889        if completions_menu_has_precedence
 7890            || !offset_selection.is_empty()
 7891            || self
 7892                .active_edit_prediction
 7893                .as_ref()
 7894                .is_some_and(|completion| {
 7895                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7896                        return false;
 7897                    };
 7898                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7899                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7900                    !invalidation_range.contains(&offset_selection.head())
 7901                })
 7902        {
 7903            self.discard_edit_prediction(false, cx);
 7904            return None;
 7905        }
 7906
 7907        self.take_active_edit_prediction(cx);
 7908        let Some(provider) = self.edit_prediction_provider() else {
 7909            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7910            return None;
 7911        };
 7912
 7913        let (buffer, cursor_buffer_position) =
 7914            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7915
 7916        self.edit_prediction_settings =
 7917            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7918
 7919        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7920
 7921        if self.edit_prediction_indent_conflict {
 7922            let cursor_point = cursor.to_point(&multibuffer);
 7923
 7924            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7925
 7926            if let Some((_, indent)) = indents.iter().next()
 7927                && indent.len == cursor_point.column
 7928            {
 7929                self.edit_prediction_indent_conflict = false;
 7930            }
 7931        }
 7932
 7933        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7934
 7935        let (completion_id, edits, edit_preview) = match edit_prediction {
 7936            edit_prediction::EditPrediction::Local {
 7937                id,
 7938                edits,
 7939                edit_preview,
 7940            } => (id, edits, edit_preview),
 7941            edit_prediction::EditPrediction::Jump {
 7942                id,
 7943                snapshot,
 7944                target,
 7945            } => {
 7946                self.stale_edit_prediction_in_menu = None;
 7947                self.active_edit_prediction = Some(EditPredictionState {
 7948                    inlay_ids: vec![],
 7949                    completion: EditPrediction::MoveOutside { snapshot, target },
 7950                    completion_id: id,
 7951                    invalidation_range: None,
 7952                });
 7953                cx.notify();
 7954                return Some(());
 7955            }
 7956        };
 7957
 7958        let edits = edits
 7959            .into_iter()
 7960            .flat_map(|(range, new_text)| {
 7961                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7962                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7963                Some((start..end, new_text))
 7964            })
 7965            .collect::<Vec<_>>();
 7966        if edits.is_empty() {
 7967            return None;
 7968        }
 7969
 7970        let first_edit_start = edits.first().unwrap().0.start;
 7971        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7972        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7973
 7974        let last_edit_end = edits.last().unwrap().0.end;
 7975        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7976        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7977
 7978        let cursor_row = cursor.to_point(&multibuffer).row;
 7979
 7980        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7981
 7982        let mut inlay_ids = Vec::new();
 7983        let invalidation_row_range;
 7984        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7985            Some(cursor_row..edit_end_row)
 7986        } else if cursor_row > edit_end_row {
 7987            Some(edit_start_row..cursor_row)
 7988        } else {
 7989            None
 7990        };
 7991        let supports_jump = self
 7992            .edit_prediction_provider
 7993            .as_ref()
 7994            .map(|provider| provider.provider.supports_jump_to_edit())
 7995            .unwrap_or(true);
 7996
 7997        let is_move = supports_jump
 7998            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7999        let completion = if is_move {
 8000            invalidation_row_range =
 8001                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8002            let target = first_edit_start;
 8003            EditPrediction::MoveWithin { target, snapshot }
 8004        } else {
 8005            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8006                && !self.edit_predictions_hidden_for_vim_mode;
 8007
 8008            if show_completions_in_buffer {
 8009                if edits
 8010                    .iter()
 8011                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8012                {
 8013                    let mut inlays = Vec::new();
 8014                    for (range, new_text) in &edits {
 8015                        let inlay = Inlay::edit_prediction(
 8016                            post_inc(&mut self.next_inlay_id),
 8017                            range.start,
 8018                            new_text.as_str(),
 8019                        );
 8020                        inlay_ids.push(inlay.id);
 8021                        inlays.push(inlay);
 8022                    }
 8023
 8024                    self.splice_inlays(&[], inlays, cx);
 8025                } else {
 8026                    let background_color = cx.theme().status().deleted_background;
 8027                    self.highlight_text::<EditPredictionHighlight>(
 8028                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8029                        HighlightStyle {
 8030                            background_color: Some(background_color),
 8031                            ..Default::default()
 8032                        },
 8033                        cx,
 8034                    );
 8035                }
 8036            }
 8037
 8038            invalidation_row_range = edit_start_row..edit_end_row;
 8039
 8040            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8041                if provider.show_tab_accept_marker() {
 8042                    EditDisplayMode::TabAccept
 8043                } else {
 8044                    EditDisplayMode::Inline
 8045                }
 8046            } else {
 8047                EditDisplayMode::DiffPopover
 8048            };
 8049
 8050            EditPrediction::Edit {
 8051                edits,
 8052                edit_preview,
 8053                display_mode,
 8054                snapshot,
 8055            }
 8056        };
 8057
 8058        let invalidation_range = multibuffer
 8059            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8060            ..multibuffer.anchor_after(Point::new(
 8061                invalidation_row_range.end,
 8062                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8063            ));
 8064
 8065        self.stale_edit_prediction_in_menu = None;
 8066        self.active_edit_prediction = Some(EditPredictionState {
 8067            inlay_ids,
 8068            completion,
 8069            completion_id,
 8070            invalidation_range: Some(invalidation_range),
 8071        });
 8072
 8073        cx.notify();
 8074
 8075        Some(())
 8076    }
 8077
 8078    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8079        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8080    }
 8081
 8082    fn clear_tasks(&mut self) {
 8083        self.tasks.clear()
 8084    }
 8085
 8086    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8087        if self.tasks.insert(key, value).is_some() {
 8088            // This case should hopefully be rare, but just in case...
 8089            log::error!(
 8090                "multiple different run targets found on a single line, only the last target will be rendered"
 8091            )
 8092        }
 8093    }
 8094
 8095    /// Get all display points of breakpoints that will be rendered within editor
 8096    ///
 8097    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8098    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8099    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8100    fn active_breakpoints(
 8101        &self,
 8102        range: Range<DisplayRow>,
 8103        window: &mut Window,
 8104        cx: &mut Context<Self>,
 8105    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8106        let mut breakpoint_display_points = HashMap::default();
 8107
 8108        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8109            return breakpoint_display_points;
 8110        };
 8111
 8112        let snapshot = self.snapshot(window, cx);
 8113
 8114        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8115        let Some(project) = self.project() else {
 8116            return breakpoint_display_points;
 8117        };
 8118
 8119        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8120            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8121
 8122        for (buffer_snapshot, range, excerpt_id) in
 8123            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8124        {
 8125            let Some(buffer) = project
 8126                .read(cx)
 8127                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8128            else {
 8129                continue;
 8130            };
 8131            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8132                &buffer,
 8133                Some(
 8134                    buffer_snapshot.anchor_before(range.start)
 8135                        ..buffer_snapshot.anchor_after(range.end),
 8136                ),
 8137                buffer_snapshot,
 8138                cx,
 8139            );
 8140            for (breakpoint, state) in breakpoints {
 8141                let multi_buffer_anchor =
 8142                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8143                let position = multi_buffer_anchor
 8144                    .to_point(multi_buffer_snapshot)
 8145                    .to_display_point(&snapshot);
 8146
 8147                breakpoint_display_points.insert(
 8148                    position.row(),
 8149                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8150                );
 8151            }
 8152        }
 8153
 8154        breakpoint_display_points
 8155    }
 8156
 8157    fn breakpoint_context_menu(
 8158        &self,
 8159        anchor: Anchor,
 8160        window: &mut Window,
 8161        cx: &mut Context<Self>,
 8162    ) -> Entity<ui::ContextMenu> {
 8163        let weak_editor = cx.weak_entity();
 8164        let focus_handle = self.focus_handle(cx);
 8165
 8166        let row = self
 8167            .buffer
 8168            .read(cx)
 8169            .snapshot(cx)
 8170            .summary_for_anchor::<Point>(&anchor)
 8171            .row;
 8172
 8173        let breakpoint = self
 8174            .breakpoint_at_row(row, window, cx)
 8175            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8176
 8177        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8178            "Edit Log Breakpoint"
 8179        } else {
 8180            "Set Log Breakpoint"
 8181        };
 8182
 8183        let condition_breakpoint_msg = if breakpoint
 8184            .as_ref()
 8185            .is_some_and(|bp| bp.1.condition.is_some())
 8186        {
 8187            "Edit Condition Breakpoint"
 8188        } else {
 8189            "Set Condition Breakpoint"
 8190        };
 8191
 8192        let hit_condition_breakpoint_msg = if breakpoint
 8193            .as_ref()
 8194            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8195        {
 8196            "Edit Hit Condition Breakpoint"
 8197        } else {
 8198            "Set Hit Condition Breakpoint"
 8199        };
 8200
 8201        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8202            "Unset Breakpoint"
 8203        } else {
 8204            "Set Breakpoint"
 8205        };
 8206
 8207        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8208
 8209        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8210            BreakpointState::Enabled => Some("Disable"),
 8211            BreakpointState::Disabled => Some("Enable"),
 8212        });
 8213
 8214        let (anchor, breakpoint) =
 8215            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8216
 8217        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8218            menu.on_blur_subscription(Subscription::new(|| {}))
 8219                .context(focus_handle)
 8220                .when(run_to_cursor, |this| {
 8221                    let weak_editor = weak_editor.clone();
 8222                    this.entry("Run to cursor", None, move |window, cx| {
 8223                        weak_editor
 8224                            .update(cx, |editor, cx| {
 8225                                editor.change_selections(
 8226                                    SelectionEffects::no_scroll(),
 8227                                    window,
 8228                                    cx,
 8229                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8230                                );
 8231                            })
 8232                            .ok();
 8233
 8234                        window.dispatch_action(Box::new(RunToCursor), cx);
 8235                    })
 8236                    .separator()
 8237                })
 8238                .when_some(toggle_state_msg, |this, msg| {
 8239                    this.entry(msg, None, {
 8240                        let weak_editor = weak_editor.clone();
 8241                        let breakpoint = breakpoint.clone();
 8242                        move |_window, cx| {
 8243                            weak_editor
 8244                                .update(cx, |this, cx| {
 8245                                    this.edit_breakpoint_at_anchor(
 8246                                        anchor,
 8247                                        breakpoint.as_ref().clone(),
 8248                                        BreakpointEditAction::InvertState,
 8249                                        cx,
 8250                                    );
 8251                                })
 8252                                .log_err();
 8253                        }
 8254                    })
 8255                })
 8256                .entry(set_breakpoint_msg, None, {
 8257                    let weak_editor = weak_editor.clone();
 8258                    let breakpoint = breakpoint.clone();
 8259                    move |_window, cx| {
 8260                        weak_editor
 8261                            .update(cx, |this, cx| {
 8262                                this.edit_breakpoint_at_anchor(
 8263                                    anchor,
 8264                                    breakpoint.as_ref().clone(),
 8265                                    BreakpointEditAction::Toggle,
 8266                                    cx,
 8267                                );
 8268                            })
 8269                            .log_err();
 8270                    }
 8271                })
 8272                .entry(log_breakpoint_msg, None, {
 8273                    let breakpoint = breakpoint.clone();
 8274                    let weak_editor = weak_editor.clone();
 8275                    move |window, cx| {
 8276                        weak_editor
 8277                            .update(cx, |this, cx| {
 8278                                this.add_edit_breakpoint_block(
 8279                                    anchor,
 8280                                    breakpoint.as_ref(),
 8281                                    BreakpointPromptEditAction::Log,
 8282                                    window,
 8283                                    cx,
 8284                                );
 8285                            })
 8286                            .log_err();
 8287                    }
 8288                })
 8289                .entry(condition_breakpoint_msg, None, {
 8290                    let breakpoint = breakpoint.clone();
 8291                    let weak_editor = weak_editor.clone();
 8292                    move |window, cx| {
 8293                        weak_editor
 8294                            .update(cx, |this, cx| {
 8295                                this.add_edit_breakpoint_block(
 8296                                    anchor,
 8297                                    breakpoint.as_ref(),
 8298                                    BreakpointPromptEditAction::Condition,
 8299                                    window,
 8300                                    cx,
 8301                                );
 8302                            })
 8303                            .log_err();
 8304                    }
 8305                })
 8306                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8307                    weak_editor
 8308                        .update(cx, |this, cx| {
 8309                            this.add_edit_breakpoint_block(
 8310                                anchor,
 8311                                breakpoint.as_ref(),
 8312                                BreakpointPromptEditAction::HitCondition,
 8313                                window,
 8314                                cx,
 8315                            );
 8316                        })
 8317                        .log_err();
 8318                })
 8319        })
 8320    }
 8321
 8322    fn render_breakpoint(
 8323        &self,
 8324        position: Anchor,
 8325        row: DisplayRow,
 8326        breakpoint: &Breakpoint,
 8327        state: Option<BreakpointSessionState>,
 8328        cx: &mut Context<Self>,
 8329    ) -> IconButton {
 8330        let is_rejected = state.is_some_and(|s| !s.verified);
 8331        // Is it a breakpoint that shows up when hovering over gutter?
 8332        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8333            (false, false),
 8334            |PhantomBreakpointIndicator {
 8335                 is_active,
 8336                 display_row,
 8337                 collides_with_existing_breakpoint,
 8338             }| {
 8339                (
 8340                    is_active && display_row == row,
 8341                    collides_with_existing_breakpoint,
 8342                )
 8343            },
 8344        );
 8345
 8346        let (color, icon) = {
 8347            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8348                (false, false) => ui::IconName::DebugBreakpoint,
 8349                (true, false) => ui::IconName::DebugLogBreakpoint,
 8350                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8351                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8352            };
 8353
 8354            let color = if is_phantom {
 8355                Color::Hint
 8356            } else if is_rejected {
 8357                Color::Disabled
 8358            } else {
 8359                Color::Debugger
 8360            };
 8361
 8362            (color, icon)
 8363        };
 8364
 8365        let breakpoint = Arc::from(breakpoint.clone());
 8366
 8367        let alt_as_text = gpui::Keystroke {
 8368            modifiers: Modifiers::secondary_key(),
 8369            ..Default::default()
 8370        };
 8371        let primary_action_text = if breakpoint.is_disabled() {
 8372            "Enable breakpoint"
 8373        } else if is_phantom && !collides_with_existing {
 8374            "Set breakpoint"
 8375        } else {
 8376            "Unset breakpoint"
 8377        };
 8378        let focus_handle = self.focus_handle.clone();
 8379
 8380        let meta = if is_rejected {
 8381            SharedString::from("No executable code is associated with this line.")
 8382        } else if collides_with_existing && !breakpoint.is_disabled() {
 8383            SharedString::from(format!(
 8384                "{alt_as_text}-click to disable,\nright-click for more options."
 8385            ))
 8386        } else {
 8387            SharedString::from("Right-click for more options.")
 8388        };
 8389        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8390            .icon_size(IconSize::XSmall)
 8391            .size(ui::ButtonSize::None)
 8392            .when(is_rejected, |this| {
 8393                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8394            })
 8395            .icon_color(color)
 8396            .style(ButtonStyle::Transparent)
 8397            .on_click(cx.listener({
 8398                move |editor, event: &ClickEvent, window, cx| {
 8399                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8400                        BreakpointEditAction::InvertState
 8401                    } else {
 8402                        BreakpointEditAction::Toggle
 8403                    };
 8404
 8405                    window.focus(&editor.focus_handle(cx));
 8406                    editor.edit_breakpoint_at_anchor(
 8407                        position,
 8408                        breakpoint.as_ref().clone(),
 8409                        edit_action,
 8410                        cx,
 8411                    );
 8412                }
 8413            }))
 8414            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8415                editor.set_breakpoint_context_menu(
 8416                    row,
 8417                    Some(position),
 8418                    event.position(),
 8419                    window,
 8420                    cx,
 8421                );
 8422            }))
 8423            .tooltip(move |window, cx| {
 8424                Tooltip::with_meta_in(
 8425                    primary_action_text,
 8426                    Some(&ToggleBreakpoint),
 8427                    meta.clone(),
 8428                    &focus_handle,
 8429                    window,
 8430                    cx,
 8431                )
 8432            })
 8433    }
 8434
 8435    fn build_tasks_context(
 8436        project: &Entity<Project>,
 8437        buffer: &Entity<Buffer>,
 8438        buffer_row: u32,
 8439        tasks: &Arc<RunnableTasks>,
 8440        cx: &mut Context<Self>,
 8441    ) -> Task<Option<task::TaskContext>> {
 8442        let position = Point::new(buffer_row, tasks.column);
 8443        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8444        let location = Location {
 8445            buffer: buffer.clone(),
 8446            range: range_start..range_start,
 8447        };
 8448        // Fill in the environmental variables from the tree-sitter captures
 8449        let mut captured_task_variables = TaskVariables::default();
 8450        for (capture_name, value) in tasks.extra_variables.clone() {
 8451            captured_task_variables.insert(
 8452                task::VariableName::Custom(capture_name.into()),
 8453                value.clone(),
 8454            );
 8455        }
 8456        project.update(cx, |project, cx| {
 8457            project.task_store().update(cx, |task_store, cx| {
 8458                task_store.task_context_for_location(captured_task_variables, location, cx)
 8459            })
 8460        })
 8461    }
 8462
 8463    pub fn spawn_nearest_task(
 8464        &mut self,
 8465        action: &SpawnNearestTask,
 8466        window: &mut Window,
 8467        cx: &mut Context<Self>,
 8468    ) {
 8469        let Some((workspace, _)) = self.workspace.clone() else {
 8470            return;
 8471        };
 8472        let Some(project) = self.project.clone() else {
 8473            return;
 8474        };
 8475
 8476        // Try to find a closest, enclosing node using tree-sitter that has a task
 8477        let Some((buffer, buffer_row, tasks)) = self
 8478            .find_enclosing_node_task(cx)
 8479            // Or find the task that's closest in row-distance.
 8480            .or_else(|| self.find_closest_task(cx))
 8481        else {
 8482            return;
 8483        };
 8484
 8485        let reveal_strategy = action.reveal;
 8486        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8487        cx.spawn_in(window, async move |_, cx| {
 8488            let context = task_context.await?;
 8489            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8490
 8491            let resolved = &mut resolved_task.resolved;
 8492            resolved.reveal = reveal_strategy;
 8493
 8494            workspace
 8495                .update_in(cx, |workspace, window, cx| {
 8496                    workspace.schedule_resolved_task(
 8497                        task_source_kind,
 8498                        resolved_task,
 8499                        false,
 8500                        window,
 8501                        cx,
 8502                    );
 8503                })
 8504                .ok()
 8505        })
 8506        .detach();
 8507    }
 8508
 8509    fn find_closest_task(
 8510        &mut self,
 8511        cx: &mut Context<Self>,
 8512    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8513        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8514
 8515        let ((buffer_id, row), tasks) = self
 8516            .tasks
 8517            .iter()
 8518            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8519
 8520        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8521        let tasks = Arc::new(tasks.to_owned());
 8522        Some((buffer, *row, tasks))
 8523    }
 8524
 8525    fn find_enclosing_node_task(
 8526        &mut self,
 8527        cx: &mut Context<Self>,
 8528    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8529        let snapshot = self.buffer.read(cx).snapshot(cx);
 8530        let offset = self.selections.newest::<usize>(cx).head();
 8531        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8532        let buffer_id = excerpt.buffer().remote_id();
 8533
 8534        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8535        let mut cursor = layer.node().walk();
 8536
 8537        while cursor.goto_first_child_for_byte(offset).is_some() {
 8538            if cursor.node().end_byte() == offset {
 8539                cursor.goto_next_sibling();
 8540            }
 8541        }
 8542
 8543        // Ascend to the smallest ancestor that contains the range and has a task.
 8544        loop {
 8545            let node = cursor.node();
 8546            let node_range = node.byte_range();
 8547            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8548
 8549            // Check if this node contains our offset
 8550            if node_range.start <= offset && node_range.end >= offset {
 8551                // If it contains offset, check for task
 8552                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8553                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8554                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8555                }
 8556            }
 8557
 8558            if !cursor.goto_parent() {
 8559                break;
 8560            }
 8561        }
 8562        None
 8563    }
 8564
 8565    fn render_run_indicator(
 8566        &self,
 8567        _style: &EditorStyle,
 8568        is_active: bool,
 8569        row: DisplayRow,
 8570        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8571        cx: &mut Context<Self>,
 8572    ) -> IconButton {
 8573        let color = Color::Muted;
 8574        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8575
 8576        IconButton::new(
 8577            ("run_indicator", row.0 as usize),
 8578            ui::IconName::PlayOutlined,
 8579        )
 8580        .shape(ui::IconButtonShape::Square)
 8581        .icon_size(IconSize::XSmall)
 8582        .icon_color(color)
 8583        .toggle_state(is_active)
 8584        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8585            let quick_launch = match e {
 8586                ClickEvent::Keyboard(_) => true,
 8587                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8588            };
 8589
 8590            window.focus(&editor.focus_handle(cx));
 8591            editor.toggle_code_actions(
 8592                &ToggleCodeActions {
 8593                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8594                    quick_launch,
 8595                },
 8596                window,
 8597                cx,
 8598            );
 8599        }))
 8600        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8601            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8602        }))
 8603    }
 8604
 8605    pub fn context_menu_visible(&self) -> bool {
 8606        !self.edit_prediction_preview_is_active()
 8607            && self
 8608                .context_menu
 8609                .borrow()
 8610                .as_ref()
 8611                .is_some_and(|menu| menu.visible())
 8612    }
 8613
 8614    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8615        self.context_menu
 8616            .borrow()
 8617            .as_ref()
 8618            .map(|menu| menu.origin())
 8619    }
 8620
 8621    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8622        self.context_menu_options = Some(options);
 8623    }
 8624
 8625    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8626    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8627
 8628    fn render_edit_prediction_popover(
 8629        &mut self,
 8630        text_bounds: &Bounds<Pixels>,
 8631        content_origin: gpui::Point<Pixels>,
 8632        right_margin: Pixels,
 8633        editor_snapshot: &EditorSnapshot,
 8634        visible_row_range: Range<DisplayRow>,
 8635        scroll_top: ScrollOffset,
 8636        scroll_bottom: ScrollOffset,
 8637        line_layouts: &[LineWithInvisibles],
 8638        line_height: Pixels,
 8639        scroll_position: gpui::Point<ScrollOffset>,
 8640        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8641        newest_selection_head: Option<DisplayPoint>,
 8642        editor_width: Pixels,
 8643        style: &EditorStyle,
 8644        window: &mut Window,
 8645        cx: &mut App,
 8646    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8647        if self.mode().is_minimap() {
 8648            return None;
 8649        }
 8650        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8651
 8652        if self.edit_prediction_visible_in_cursor_popover(true) {
 8653            return None;
 8654        }
 8655
 8656        match &active_edit_prediction.completion {
 8657            EditPrediction::MoveWithin { target, .. } => {
 8658                let target_display_point = target.to_display_point(editor_snapshot);
 8659
 8660                if self.edit_prediction_requires_modifier() {
 8661                    if !self.edit_prediction_preview_is_active() {
 8662                        return None;
 8663                    }
 8664
 8665                    self.render_edit_prediction_modifier_jump_popover(
 8666                        text_bounds,
 8667                        content_origin,
 8668                        visible_row_range,
 8669                        line_layouts,
 8670                        line_height,
 8671                        scroll_pixel_position,
 8672                        newest_selection_head,
 8673                        target_display_point,
 8674                        window,
 8675                        cx,
 8676                    )
 8677                } else {
 8678                    self.render_edit_prediction_eager_jump_popover(
 8679                        text_bounds,
 8680                        content_origin,
 8681                        editor_snapshot,
 8682                        visible_row_range,
 8683                        scroll_top,
 8684                        scroll_bottom,
 8685                        line_height,
 8686                        scroll_pixel_position,
 8687                        target_display_point,
 8688                        editor_width,
 8689                        window,
 8690                        cx,
 8691                    )
 8692                }
 8693            }
 8694            EditPrediction::Edit {
 8695                display_mode: EditDisplayMode::Inline,
 8696                ..
 8697            } => None,
 8698            EditPrediction::Edit {
 8699                display_mode: EditDisplayMode::TabAccept,
 8700                edits,
 8701                ..
 8702            } => {
 8703                let range = &edits.first()?.0;
 8704                let target_display_point = range.end.to_display_point(editor_snapshot);
 8705
 8706                self.render_edit_prediction_end_of_line_popover(
 8707                    "Accept",
 8708                    editor_snapshot,
 8709                    visible_row_range,
 8710                    target_display_point,
 8711                    line_height,
 8712                    scroll_pixel_position,
 8713                    content_origin,
 8714                    editor_width,
 8715                    window,
 8716                    cx,
 8717                )
 8718            }
 8719            EditPrediction::Edit {
 8720                edits,
 8721                edit_preview,
 8722                display_mode: EditDisplayMode::DiffPopover,
 8723                snapshot,
 8724            } => self.render_edit_prediction_diff_popover(
 8725                text_bounds,
 8726                content_origin,
 8727                right_margin,
 8728                editor_snapshot,
 8729                visible_row_range,
 8730                line_layouts,
 8731                line_height,
 8732                scroll_position,
 8733                scroll_pixel_position,
 8734                newest_selection_head,
 8735                editor_width,
 8736                style,
 8737                edits,
 8738                edit_preview,
 8739                snapshot,
 8740                window,
 8741                cx,
 8742            ),
 8743            EditPrediction::MoveOutside { snapshot, .. } => {
 8744                let file_name = snapshot
 8745                    .file()
 8746                    .map(|file| file.file_name(cx))
 8747                    .unwrap_or("untitled");
 8748                let mut element = self
 8749                    .render_edit_prediction_line_popover(
 8750                        format!("Jump to {file_name}"),
 8751                        Some(IconName::ZedPredict),
 8752                        window,
 8753                        cx,
 8754                    )
 8755                    .into_any();
 8756
 8757                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8758                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8759                let origin_y = text_bounds.size.height - size.height - px(30.);
 8760                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8761                element.prepaint_at(origin, window, cx);
 8762
 8763                Some((element, origin))
 8764            }
 8765        }
 8766    }
 8767
 8768    fn render_edit_prediction_modifier_jump_popover(
 8769        &mut self,
 8770        text_bounds: &Bounds<Pixels>,
 8771        content_origin: gpui::Point<Pixels>,
 8772        visible_row_range: Range<DisplayRow>,
 8773        line_layouts: &[LineWithInvisibles],
 8774        line_height: Pixels,
 8775        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8776        newest_selection_head: Option<DisplayPoint>,
 8777        target_display_point: DisplayPoint,
 8778        window: &mut Window,
 8779        cx: &mut App,
 8780    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8781        let scrolled_content_origin =
 8782            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8783
 8784        const SCROLL_PADDING_Y: Pixels = px(12.);
 8785
 8786        if target_display_point.row() < visible_row_range.start {
 8787            return self.render_edit_prediction_scroll_popover(
 8788                |_| SCROLL_PADDING_Y,
 8789                IconName::ArrowUp,
 8790                visible_row_range,
 8791                line_layouts,
 8792                newest_selection_head,
 8793                scrolled_content_origin,
 8794                window,
 8795                cx,
 8796            );
 8797        } else if target_display_point.row() >= visible_row_range.end {
 8798            return self.render_edit_prediction_scroll_popover(
 8799                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8800                IconName::ArrowDown,
 8801                visible_row_range,
 8802                line_layouts,
 8803                newest_selection_head,
 8804                scrolled_content_origin,
 8805                window,
 8806                cx,
 8807            );
 8808        }
 8809
 8810        const POLE_WIDTH: Pixels = px(2.);
 8811
 8812        let line_layout =
 8813            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8814        let target_column = target_display_point.column() as usize;
 8815
 8816        let target_x = line_layout.x_for_index(target_column);
 8817        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8818            - scroll_pixel_position.y;
 8819
 8820        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8821
 8822        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8823        border_color.l += 0.001;
 8824
 8825        let mut element = v_flex()
 8826            .items_end()
 8827            .when(flag_on_right, |el| el.items_start())
 8828            .child(if flag_on_right {
 8829                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8830                    .rounded_bl(px(0.))
 8831                    .rounded_tl(px(0.))
 8832                    .border_l_2()
 8833                    .border_color(border_color)
 8834            } else {
 8835                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8836                    .rounded_br(px(0.))
 8837                    .rounded_tr(px(0.))
 8838                    .border_r_2()
 8839                    .border_color(border_color)
 8840            })
 8841            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8842            .into_any();
 8843
 8844        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8845
 8846        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8847            - point(
 8848                if flag_on_right {
 8849                    POLE_WIDTH
 8850                } else {
 8851                    size.width - POLE_WIDTH
 8852                },
 8853                size.height - line_height,
 8854            );
 8855
 8856        origin.x = origin.x.max(content_origin.x);
 8857
 8858        element.prepaint_at(origin, window, cx);
 8859
 8860        Some((element, origin))
 8861    }
 8862
 8863    fn render_edit_prediction_scroll_popover(
 8864        &mut self,
 8865        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8866        scroll_icon: IconName,
 8867        visible_row_range: Range<DisplayRow>,
 8868        line_layouts: &[LineWithInvisibles],
 8869        newest_selection_head: Option<DisplayPoint>,
 8870        scrolled_content_origin: gpui::Point<Pixels>,
 8871        window: &mut Window,
 8872        cx: &mut App,
 8873    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8874        let mut element = self
 8875            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8876            .into_any();
 8877
 8878        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8879
 8880        let cursor = newest_selection_head?;
 8881        let cursor_row_layout =
 8882            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8883        let cursor_column = cursor.column() as usize;
 8884
 8885        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8886
 8887        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8888
 8889        element.prepaint_at(origin, window, cx);
 8890        Some((element, origin))
 8891    }
 8892
 8893    fn render_edit_prediction_eager_jump_popover(
 8894        &mut self,
 8895        text_bounds: &Bounds<Pixels>,
 8896        content_origin: gpui::Point<Pixels>,
 8897        editor_snapshot: &EditorSnapshot,
 8898        visible_row_range: Range<DisplayRow>,
 8899        scroll_top: ScrollOffset,
 8900        scroll_bottom: ScrollOffset,
 8901        line_height: Pixels,
 8902        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8903        target_display_point: DisplayPoint,
 8904        editor_width: Pixels,
 8905        window: &mut Window,
 8906        cx: &mut App,
 8907    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8908        if target_display_point.row().as_f64() < scroll_top {
 8909            let mut element = self
 8910                .render_edit_prediction_line_popover(
 8911                    "Jump to Edit",
 8912                    Some(IconName::ArrowUp),
 8913                    window,
 8914                    cx,
 8915                )
 8916                .into_any();
 8917
 8918            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8919            let offset = point(
 8920                (text_bounds.size.width - size.width) / 2.,
 8921                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8922            );
 8923
 8924            let origin = text_bounds.origin + offset;
 8925            element.prepaint_at(origin, window, cx);
 8926            Some((element, origin))
 8927        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8928            let mut element = self
 8929                .render_edit_prediction_line_popover(
 8930                    "Jump to Edit",
 8931                    Some(IconName::ArrowDown),
 8932                    window,
 8933                    cx,
 8934                )
 8935                .into_any();
 8936
 8937            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8938            let offset = point(
 8939                (text_bounds.size.width - size.width) / 2.,
 8940                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8941            );
 8942
 8943            let origin = text_bounds.origin + offset;
 8944            element.prepaint_at(origin, window, cx);
 8945            Some((element, origin))
 8946        } else {
 8947            self.render_edit_prediction_end_of_line_popover(
 8948                "Jump to Edit",
 8949                editor_snapshot,
 8950                visible_row_range,
 8951                target_display_point,
 8952                line_height,
 8953                scroll_pixel_position,
 8954                content_origin,
 8955                editor_width,
 8956                window,
 8957                cx,
 8958            )
 8959        }
 8960    }
 8961
 8962    fn render_edit_prediction_end_of_line_popover(
 8963        self: &mut Editor,
 8964        label: &'static str,
 8965        editor_snapshot: &EditorSnapshot,
 8966        visible_row_range: Range<DisplayRow>,
 8967        target_display_point: DisplayPoint,
 8968        line_height: Pixels,
 8969        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8970        content_origin: gpui::Point<Pixels>,
 8971        editor_width: Pixels,
 8972        window: &mut Window,
 8973        cx: &mut App,
 8974    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8975        let target_line_end = DisplayPoint::new(
 8976            target_display_point.row(),
 8977            editor_snapshot.line_len(target_display_point.row()),
 8978        );
 8979
 8980        let mut element = self
 8981            .render_edit_prediction_line_popover(label, None, window, cx)
 8982            .into_any();
 8983
 8984        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8985
 8986        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8987
 8988        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8989        let mut origin = start_point
 8990            + line_origin
 8991            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8992        origin.x = origin.x.max(content_origin.x);
 8993
 8994        let max_x = content_origin.x + editor_width - size.width;
 8995
 8996        if origin.x > max_x {
 8997            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8998
 8999            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9000                origin.y += offset;
 9001                IconName::ArrowUp
 9002            } else {
 9003                origin.y -= offset;
 9004                IconName::ArrowDown
 9005            };
 9006
 9007            element = self
 9008                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9009                .into_any();
 9010
 9011            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9012
 9013            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9014        }
 9015
 9016        element.prepaint_at(origin, window, cx);
 9017        Some((element, origin))
 9018    }
 9019
 9020    fn render_edit_prediction_diff_popover(
 9021        self: &Editor,
 9022        text_bounds: &Bounds<Pixels>,
 9023        content_origin: gpui::Point<Pixels>,
 9024        right_margin: Pixels,
 9025        editor_snapshot: &EditorSnapshot,
 9026        visible_row_range: Range<DisplayRow>,
 9027        line_layouts: &[LineWithInvisibles],
 9028        line_height: Pixels,
 9029        scroll_position: gpui::Point<ScrollOffset>,
 9030        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9031        newest_selection_head: Option<DisplayPoint>,
 9032        editor_width: Pixels,
 9033        style: &EditorStyle,
 9034        edits: &Vec<(Range<Anchor>, String)>,
 9035        edit_preview: &Option<language::EditPreview>,
 9036        snapshot: &language::BufferSnapshot,
 9037        window: &mut Window,
 9038        cx: &mut App,
 9039    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9040        let edit_start = edits
 9041            .first()
 9042            .unwrap()
 9043            .0
 9044            .start
 9045            .to_display_point(editor_snapshot);
 9046        let edit_end = edits
 9047            .last()
 9048            .unwrap()
 9049            .0
 9050            .end
 9051            .to_display_point(editor_snapshot);
 9052
 9053        let is_visible = visible_row_range.contains(&edit_start.row())
 9054            || visible_row_range.contains(&edit_end.row());
 9055        if !is_visible {
 9056            return None;
 9057        }
 9058
 9059        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9060            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9061        } else {
 9062            // Fallback for providers without edit_preview
 9063            crate::edit_prediction_fallback_text(edits, cx)
 9064        };
 9065
 9066        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9067        let line_count = highlighted_edits.text.lines().count();
 9068
 9069        const BORDER_WIDTH: Pixels = px(1.);
 9070
 9071        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9072        let has_keybind = keybind.is_some();
 9073
 9074        let mut element = h_flex()
 9075            .items_start()
 9076            .child(
 9077                h_flex()
 9078                    .bg(cx.theme().colors().editor_background)
 9079                    .border(BORDER_WIDTH)
 9080                    .shadow_xs()
 9081                    .border_color(cx.theme().colors().border)
 9082                    .rounded_l_lg()
 9083                    .when(line_count > 1, |el| el.rounded_br_lg())
 9084                    .pr_1()
 9085                    .child(styled_text),
 9086            )
 9087            .child(
 9088                h_flex()
 9089                    .h(line_height + BORDER_WIDTH * 2.)
 9090                    .px_1p5()
 9091                    .gap_1()
 9092                    // Workaround: For some reason, there's a gap if we don't do this
 9093                    .ml(-BORDER_WIDTH)
 9094                    .shadow(vec![gpui::BoxShadow {
 9095                        color: gpui::black().opacity(0.05),
 9096                        offset: point(px(1.), px(1.)),
 9097                        blur_radius: px(2.),
 9098                        spread_radius: px(0.),
 9099                    }])
 9100                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9101                    .border(BORDER_WIDTH)
 9102                    .border_color(cx.theme().colors().border)
 9103                    .rounded_r_lg()
 9104                    .id("edit_prediction_diff_popover_keybind")
 9105                    .when(!has_keybind, |el| {
 9106                        let status_colors = cx.theme().status();
 9107
 9108                        el.bg(status_colors.error_background)
 9109                            .border_color(status_colors.error.opacity(0.6))
 9110                            .child(Icon::new(IconName::Info).color(Color::Error))
 9111                            .cursor_default()
 9112                            .hoverable_tooltip(move |_window, cx| {
 9113                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9114                            })
 9115                    })
 9116                    .children(keybind),
 9117            )
 9118            .into_any();
 9119
 9120        let longest_row =
 9121            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9122        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9123            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9124        } else {
 9125            layout_line(
 9126                longest_row,
 9127                editor_snapshot,
 9128                style,
 9129                editor_width,
 9130                |_| false,
 9131                window,
 9132                cx,
 9133            )
 9134            .width
 9135        };
 9136
 9137        let viewport_bounds =
 9138            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9139                right: -right_margin,
 9140                ..Default::default()
 9141            });
 9142
 9143        let x_after_longest = Pixels::from(
 9144            ScrollPixelOffset::from(
 9145                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9146            ) - scroll_pixel_position.x,
 9147        );
 9148
 9149        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9150
 9151        // Fully visible if it can be displayed within the window (allow overlapping other
 9152        // panes). However, this is only allowed if the popover starts within text_bounds.
 9153        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9154            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9155
 9156        let mut origin = if can_position_to_the_right {
 9157            point(
 9158                x_after_longest,
 9159                text_bounds.origin.y
 9160                    + Pixels::from(
 9161                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9162                            - scroll_pixel_position.y,
 9163                    ),
 9164            )
 9165        } else {
 9166            let cursor_row = newest_selection_head.map(|head| head.row());
 9167            let above_edit = edit_start
 9168                .row()
 9169                .0
 9170                .checked_sub(line_count as u32)
 9171                .map(DisplayRow);
 9172            let below_edit = Some(edit_end.row() + 1);
 9173            let above_cursor =
 9174                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9175            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9176
 9177            // Place the edit popover adjacent to the edit if there is a location
 9178            // available that is onscreen and does not obscure the cursor. Otherwise,
 9179            // place it adjacent to the cursor.
 9180            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9181                .into_iter()
 9182                .flatten()
 9183                .find(|&start_row| {
 9184                    let end_row = start_row + line_count as u32;
 9185                    visible_row_range.contains(&start_row)
 9186                        && visible_row_range.contains(&end_row)
 9187                        && cursor_row
 9188                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9189                })?;
 9190
 9191            content_origin
 9192                + point(
 9193                    Pixels::from(-scroll_pixel_position.x),
 9194                    Pixels::from(
 9195                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9196                    ),
 9197                )
 9198        };
 9199
 9200        origin.x -= BORDER_WIDTH;
 9201
 9202        window.defer_draw(element, origin, 1);
 9203
 9204        // Do not return an element, since it will already be drawn due to defer_draw.
 9205        None
 9206    }
 9207
 9208    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9209        px(30.)
 9210    }
 9211
 9212    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9213        if self.read_only(cx) {
 9214            cx.theme().players().read_only()
 9215        } else {
 9216            self.style.as_ref().unwrap().local_player
 9217        }
 9218    }
 9219
 9220    fn render_edit_prediction_accept_keybind(
 9221        &self,
 9222        window: &mut Window,
 9223        cx: &App,
 9224    ) -> Option<AnyElement> {
 9225        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9226        let accept_keystroke = accept_binding.keystroke()?;
 9227
 9228        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9229
 9230        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9231            Color::Accent
 9232        } else {
 9233            Color::Muted
 9234        };
 9235
 9236        h_flex()
 9237            .px_0p5()
 9238            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9239            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9240            .text_size(TextSize::XSmall.rems(cx))
 9241            .child(h_flex().children(ui::render_modifiers(
 9242                accept_keystroke.modifiers(),
 9243                PlatformStyle::platform(),
 9244                Some(modifiers_color),
 9245                Some(IconSize::XSmall.rems().into()),
 9246                true,
 9247            )))
 9248            .when(is_platform_style_mac, |parent| {
 9249                parent.child(accept_keystroke.key().to_string())
 9250            })
 9251            .when(!is_platform_style_mac, |parent| {
 9252                parent.child(
 9253                    Key::new(
 9254                        util::capitalize(accept_keystroke.key()),
 9255                        Some(Color::Default),
 9256                    )
 9257                    .size(Some(IconSize::XSmall.rems().into())),
 9258                )
 9259            })
 9260            .into_any()
 9261            .into()
 9262    }
 9263
 9264    fn render_edit_prediction_line_popover(
 9265        &self,
 9266        label: impl Into<SharedString>,
 9267        icon: Option<IconName>,
 9268        window: &mut Window,
 9269        cx: &App,
 9270    ) -> Stateful<Div> {
 9271        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9272
 9273        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9274        let has_keybind = keybind.is_some();
 9275
 9276        h_flex()
 9277            .id("ep-line-popover")
 9278            .py_0p5()
 9279            .pl_1()
 9280            .pr(padding_right)
 9281            .gap_1()
 9282            .rounded_md()
 9283            .border_1()
 9284            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9285            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9286            .shadow_xs()
 9287            .when(!has_keybind, |el| {
 9288                let status_colors = cx.theme().status();
 9289
 9290                el.bg(status_colors.error_background)
 9291                    .border_color(status_colors.error.opacity(0.6))
 9292                    .pl_2()
 9293                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9294                    .cursor_default()
 9295                    .hoverable_tooltip(move |_window, cx| {
 9296                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9297                    })
 9298            })
 9299            .children(keybind)
 9300            .child(
 9301                Label::new(label)
 9302                    .size(LabelSize::Small)
 9303                    .when(!has_keybind, |el| {
 9304                        el.color(cx.theme().status().error.into()).strikethrough()
 9305                    }),
 9306            )
 9307            .when(!has_keybind, |el| {
 9308                el.child(
 9309                    h_flex().ml_1().child(
 9310                        Icon::new(IconName::Info)
 9311                            .size(IconSize::Small)
 9312                            .color(cx.theme().status().error.into()),
 9313                    ),
 9314                )
 9315            })
 9316            .when_some(icon, |element, icon| {
 9317                element.child(
 9318                    div()
 9319                        .mt(px(1.5))
 9320                        .child(Icon::new(icon).size(IconSize::Small)),
 9321                )
 9322            })
 9323    }
 9324
 9325    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9326        let accent_color = cx.theme().colors().text_accent;
 9327        let editor_bg_color = cx.theme().colors().editor_background;
 9328        editor_bg_color.blend(accent_color.opacity(0.1))
 9329    }
 9330
 9331    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9332        let accent_color = cx.theme().colors().text_accent;
 9333        let editor_bg_color = cx.theme().colors().editor_background;
 9334        editor_bg_color.blend(accent_color.opacity(0.6))
 9335    }
 9336    fn get_prediction_provider_icon_name(
 9337        provider: &Option<RegisteredEditPredictionProvider>,
 9338    ) -> IconName {
 9339        match provider {
 9340            Some(provider) => match provider.provider.name() {
 9341                "copilot" => IconName::Copilot,
 9342                "supermaven" => IconName::Supermaven,
 9343                _ => IconName::ZedPredict,
 9344            },
 9345            None => IconName::ZedPredict,
 9346        }
 9347    }
 9348
 9349    fn render_edit_prediction_cursor_popover(
 9350        &self,
 9351        min_width: Pixels,
 9352        max_width: Pixels,
 9353        cursor_point: Point,
 9354        style: &EditorStyle,
 9355        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9356        _window: &Window,
 9357        cx: &mut Context<Editor>,
 9358    ) -> Option<AnyElement> {
 9359        let provider = self.edit_prediction_provider.as_ref()?;
 9360        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9361
 9362        let is_refreshing = provider.provider.is_refreshing(cx);
 9363
 9364        fn pending_completion_container(icon: IconName) -> Div {
 9365            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9366        }
 9367
 9368        let completion = match &self.active_edit_prediction {
 9369            Some(prediction) => {
 9370                if !self.has_visible_completions_menu() {
 9371                    const RADIUS: Pixels = px(6.);
 9372                    const BORDER_WIDTH: Pixels = px(1.);
 9373
 9374                    return Some(
 9375                        h_flex()
 9376                            .elevation_2(cx)
 9377                            .border(BORDER_WIDTH)
 9378                            .border_color(cx.theme().colors().border)
 9379                            .when(accept_keystroke.is_none(), |el| {
 9380                                el.border_color(cx.theme().status().error)
 9381                            })
 9382                            .rounded(RADIUS)
 9383                            .rounded_tl(px(0.))
 9384                            .overflow_hidden()
 9385                            .child(div().px_1p5().child(match &prediction.completion {
 9386                                EditPrediction::MoveWithin { target, snapshot } => {
 9387                                    use text::ToPoint as _;
 9388                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9389                                    {
 9390                                        Icon::new(IconName::ZedPredictDown)
 9391                                    } else {
 9392                                        Icon::new(IconName::ZedPredictUp)
 9393                                    }
 9394                                }
 9395                                EditPrediction::MoveOutside { .. } => {
 9396                                    // TODO [zeta2] custom icon for external jump?
 9397                                    Icon::new(provider_icon)
 9398                                }
 9399                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9400                            }))
 9401                            .child(
 9402                                h_flex()
 9403                                    .gap_1()
 9404                                    .py_1()
 9405                                    .px_2()
 9406                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9407                                    .border_l_1()
 9408                                    .border_color(cx.theme().colors().border)
 9409                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9410                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9411                                        el.child(
 9412                                            Label::new("Hold")
 9413                                                .size(LabelSize::Small)
 9414                                                .when(accept_keystroke.is_none(), |el| {
 9415                                                    el.strikethrough()
 9416                                                })
 9417                                                .line_height_style(LineHeightStyle::UiLabel),
 9418                                        )
 9419                                    })
 9420                                    .id("edit_prediction_cursor_popover_keybind")
 9421                                    .when(accept_keystroke.is_none(), |el| {
 9422                                        let status_colors = cx.theme().status();
 9423
 9424                                        el.bg(status_colors.error_background)
 9425                                            .border_color(status_colors.error.opacity(0.6))
 9426                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9427                                            .cursor_default()
 9428                                            .hoverable_tooltip(move |_window, cx| {
 9429                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9430                                                    .into()
 9431                                            })
 9432                                    })
 9433                                    .when_some(
 9434                                        accept_keystroke.as_ref(),
 9435                                        |el, accept_keystroke| {
 9436                                            el.child(h_flex().children(ui::render_modifiers(
 9437                                                accept_keystroke.modifiers(),
 9438                                                PlatformStyle::platform(),
 9439                                                Some(Color::Default),
 9440                                                Some(IconSize::XSmall.rems().into()),
 9441                                                false,
 9442                                            )))
 9443                                        },
 9444                                    ),
 9445                            )
 9446                            .into_any(),
 9447                    );
 9448                }
 9449
 9450                self.render_edit_prediction_cursor_popover_preview(
 9451                    prediction,
 9452                    cursor_point,
 9453                    style,
 9454                    cx,
 9455                )?
 9456            }
 9457
 9458            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9459                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9460                    stale_completion,
 9461                    cursor_point,
 9462                    style,
 9463                    cx,
 9464                )?,
 9465
 9466                None => pending_completion_container(provider_icon)
 9467                    .child(Label::new("...").size(LabelSize::Small)),
 9468            },
 9469
 9470            None => pending_completion_container(provider_icon)
 9471                .child(Label::new("...").size(LabelSize::Small)),
 9472        };
 9473
 9474        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9475            completion
 9476                .with_animation(
 9477                    "loading-completion",
 9478                    Animation::new(Duration::from_secs(2))
 9479                        .repeat()
 9480                        .with_easing(pulsating_between(0.4, 0.8)),
 9481                    |label, delta| label.opacity(delta),
 9482                )
 9483                .into_any_element()
 9484        } else {
 9485            completion.into_any_element()
 9486        };
 9487
 9488        let has_completion = self.active_edit_prediction.is_some();
 9489
 9490        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9491        Some(
 9492            h_flex()
 9493                .min_w(min_width)
 9494                .max_w(max_width)
 9495                .flex_1()
 9496                .elevation_2(cx)
 9497                .border_color(cx.theme().colors().border)
 9498                .child(
 9499                    div()
 9500                        .flex_1()
 9501                        .py_1()
 9502                        .px_2()
 9503                        .overflow_hidden()
 9504                        .child(completion),
 9505                )
 9506                .when_some(accept_keystroke, |el, accept_keystroke| {
 9507                    if !accept_keystroke.modifiers().modified() {
 9508                        return el;
 9509                    }
 9510
 9511                    el.child(
 9512                        h_flex()
 9513                            .h_full()
 9514                            .border_l_1()
 9515                            .rounded_r_lg()
 9516                            .border_color(cx.theme().colors().border)
 9517                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9518                            .gap_1()
 9519                            .py_1()
 9520                            .px_2()
 9521                            .child(
 9522                                h_flex()
 9523                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9524                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9525                                    .child(h_flex().children(ui::render_modifiers(
 9526                                        accept_keystroke.modifiers(),
 9527                                        PlatformStyle::platform(),
 9528                                        Some(if !has_completion {
 9529                                            Color::Muted
 9530                                        } else {
 9531                                            Color::Default
 9532                                        }),
 9533                                        None,
 9534                                        false,
 9535                                    ))),
 9536                            )
 9537                            .child(Label::new("Preview").into_any_element())
 9538                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9539                    )
 9540                })
 9541                .into_any(),
 9542        )
 9543    }
 9544
 9545    fn render_edit_prediction_cursor_popover_preview(
 9546        &self,
 9547        completion: &EditPredictionState,
 9548        cursor_point: Point,
 9549        style: &EditorStyle,
 9550        cx: &mut Context<Editor>,
 9551    ) -> Option<Div> {
 9552        use text::ToPoint as _;
 9553
 9554        fn render_relative_row_jump(
 9555            prefix: impl Into<String>,
 9556            current_row: u32,
 9557            target_row: u32,
 9558        ) -> Div {
 9559            let (row_diff, arrow) = if target_row < current_row {
 9560                (current_row - target_row, IconName::ArrowUp)
 9561            } else {
 9562                (target_row - current_row, IconName::ArrowDown)
 9563            };
 9564
 9565            h_flex()
 9566                .child(
 9567                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9568                        .color(Color::Muted)
 9569                        .size(LabelSize::Small),
 9570                )
 9571                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9572        }
 9573
 9574        let supports_jump = self
 9575            .edit_prediction_provider
 9576            .as_ref()
 9577            .map(|provider| provider.provider.supports_jump_to_edit())
 9578            .unwrap_or(true);
 9579
 9580        match &completion.completion {
 9581            EditPrediction::MoveWithin {
 9582                target, snapshot, ..
 9583            } => {
 9584                if !supports_jump {
 9585                    return None;
 9586                }
 9587
 9588                Some(
 9589                    h_flex()
 9590                        .px_2()
 9591                        .gap_2()
 9592                        .flex_1()
 9593                        .child(
 9594                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9595                                Icon::new(IconName::ZedPredictDown)
 9596                            } else {
 9597                                Icon::new(IconName::ZedPredictUp)
 9598                            },
 9599                        )
 9600                        .child(Label::new("Jump to Edit")),
 9601                )
 9602            }
 9603            EditPrediction::MoveOutside { snapshot, .. } => {
 9604                let file_name = snapshot
 9605                    .file()
 9606                    .map(|file| file.file_name(cx))
 9607                    .unwrap_or("untitled");
 9608                Some(
 9609                    h_flex()
 9610                        .px_2()
 9611                        .gap_2()
 9612                        .flex_1()
 9613                        .child(Icon::new(IconName::ZedPredict))
 9614                        .child(Label::new(format!("Jump to {file_name}"))),
 9615                )
 9616            }
 9617            EditPrediction::Edit {
 9618                edits,
 9619                edit_preview,
 9620                snapshot,
 9621                display_mode: _,
 9622            } => {
 9623                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9624
 9625                let (highlighted_edits, has_more_lines) =
 9626                    if let Some(edit_preview) = edit_preview.as_ref() {
 9627                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9628                            .first_line_preview()
 9629                    } else {
 9630                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9631                    };
 9632
 9633                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9634                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9635
 9636                let preview = h_flex()
 9637                    .gap_1()
 9638                    .min_w_16()
 9639                    .child(styled_text)
 9640                    .when(has_more_lines, |parent| parent.child(""));
 9641
 9642                let left = if supports_jump && first_edit_row != cursor_point.row {
 9643                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9644                        .into_any_element()
 9645                } else {
 9646                    let icon_name =
 9647                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9648                    Icon::new(icon_name).into_any_element()
 9649                };
 9650
 9651                Some(
 9652                    h_flex()
 9653                        .h_full()
 9654                        .flex_1()
 9655                        .gap_2()
 9656                        .pr_1()
 9657                        .overflow_x_hidden()
 9658                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9659                        .child(left)
 9660                        .child(preview),
 9661                )
 9662            }
 9663        }
 9664    }
 9665
 9666    pub fn render_context_menu(
 9667        &self,
 9668        style: &EditorStyle,
 9669        max_height_in_lines: u32,
 9670        window: &mut Window,
 9671        cx: &mut Context<Editor>,
 9672    ) -> Option<AnyElement> {
 9673        let menu = self.context_menu.borrow();
 9674        let menu = menu.as_ref()?;
 9675        if !menu.visible() {
 9676            return None;
 9677        };
 9678        Some(menu.render(style, max_height_in_lines, window, cx))
 9679    }
 9680
 9681    fn render_context_menu_aside(
 9682        &mut self,
 9683        max_size: Size<Pixels>,
 9684        window: &mut Window,
 9685        cx: &mut Context<Editor>,
 9686    ) -> Option<AnyElement> {
 9687        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9688            if menu.visible() {
 9689                menu.render_aside(max_size, window, cx)
 9690            } else {
 9691                None
 9692            }
 9693        })
 9694    }
 9695
 9696    fn hide_context_menu(
 9697        &mut self,
 9698        window: &mut Window,
 9699        cx: &mut Context<Self>,
 9700    ) -> Option<CodeContextMenu> {
 9701        cx.notify();
 9702        self.completion_tasks.clear();
 9703        let context_menu = self.context_menu.borrow_mut().take();
 9704        self.stale_edit_prediction_in_menu.take();
 9705        self.update_visible_edit_prediction(window, cx);
 9706        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9707            && let Some(completion_provider) = &self.completion_provider
 9708        {
 9709            completion_provider.selection_changed(None, window, cx);
 9710        }
 9711        context_menu
 9712    }
 9713
 9714    fn show_snippet_choices(
 9715        &mut self,
 9716        choices: &Vec<String>,
 9717        selection: Range<Anchor>,
 9718        cx: &mut Context<Self>,
 9719    ) {
 9720        let Some((_, buffer, _)) = self
 9721            .buffer()
 9722            .read(cx)
 9723            .excerpt_containing(selection.start, cx)
 9724        else {
 9725            return;
 9726        };
 9727        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9728        else {
 9729            return;
 9730        };
 9731        if buffer != end_buffer {
 9732            log::error!("expected anchor range to have matching buffer IDs");
 9733            return;
 9734        }
 9735
 9736        let id = post_inc(&mut self.next_completion_id);
 9737        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9738        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9739            CompletionsMenu::new_snippet_choices(
 9740                id,
 9741                true,
 9742                choices,
 9743                selection,
 9744                buffer,
 9745                snippet_sort_order,
 9746            ),
 9747        ));
 9748    }
 9749
 9750    pub fn insert_snippet(
 9751        &mut self,
 9752        insertion_ranges: &[Range<usize>],
 9753        snippet: Snippet,
 9754        window: &mut Window,
 9755        cx: &mut Context<Self>,
 9756    ) -> Result<()> {
 9757        struct Tabstop<T> {
 9758            is_end_tabstop: bool,
 9759            ranges: Vec<Range<T>>,
 9760            choices: Option<Vec<String>>,
 9761        }
 9762
 9763        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9764            let snippet_text: Arc<str> = snippet.text.clone().into();
 9765            let edits = insertion_ranges
 9766                .iter()
 9767                .cloned()
 9768                .map(|range| (range, snippet_text.clone()));
 9769            let autoindent_mode = AutoindentMode::Block {
 9770                original_indent_columns: Vec::new(),
 9771            };
 9772            buffer.edit(edits, Some(autoindent_mode), cx);
 9773
 9774            let snapshot = &*buffer.read(cx);
 9775            let snippet = &snippet;
 9776            snippet
 9777                .tabstops
 9778                .iter()
 9779                .map(|tabstop| {
 9780                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9781                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9782                    });
 9783                    let mut tabstop_ranges = tabstop
 9784                        .ranges
 9785                        .iter()
 9786                        .flat_map(|tabstop_range| {
 9787                            let mut delta = 0_isize;
 9788                            insertion_ranges.iter().map(move |insertion_range| {
 9789                                let insertion_start = insertion_range.start as isize + delta;
 9790                                delta +=
 9791                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9792
 9793                                let start = ((insertion_start + tabstop_range.start) as usize)
 9794                                    .min(snapshot.len());
 9795                                let end = ((insertion_start + tabstop_range.end) as usize)
 9796                                    .min(snapshot.len());
 9797                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9798                            })
 9799                        })
 9800                        .collect::<Vec<_>>();
 9801                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9802
 9803                    Tabstop {
 9804                        is_end_tabstop,
 9805                        ranges: tabstop_ranges,
 9806                        choices: tabstop.choices.clone(),
 9807                    }
 9808                })
 9809                .collect::<Vec<_>>()
 9810        });
 9811        if let Some(tabstop) = tabstops.first() {
 9812            self.change_selections(Default::default(), window, cx, |s| {
 9813                // Reverse order so that the first range is the newest created selection.
 9814                // Completions will use it and autoscroll will prioritize it.
 9815                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9816            });
 9817
 9818            if let Some(choices) = &tabstop.choices
 9819                && let Some(selection) = tabstop.ranges.first()
 9820            {
 9821                self.show_snippet_choices(choices, selection.clone(), cx)
 9822            }
 9823
 9824            // If we're already at the last tabstop and it's at the end of the snippet,
 9825            // we're done, we don't need to keep the state around.
 9826            if !tabstop.is_end_tabstop {
 9827                let choices = tabstops
 9828                    .iter()
 9829                    .map(|tabstop| tabstop.choices.clone())
 9830                    .collect();
 9831
 9832                let ranges = tabstops
 9833                    .into_iter()
 9834                    .map(|tabstop| tabstop.ranges)
 9835                    .collect::<Vec<_>>();
 9836
 9837                self.snippet_stack.push(SnippetState {
 9838                    active_index: 0,
 9839                    ranges,
 9840                    choices,
 9841                });
 9842            }
 9843
 9844            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9845            if self.autoclose_regions.is_empty() {
 9846                let snapshot = self.buffer.read(cx).snapshot(cx);
 9847                let mut all_selections = self.selections.all::<Point>(cx);
 9848                for selection in &mut all_selections {
 9849                    let selection_head = selection.head();
 9850                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9851                        continue;
 9852                    };
 9853
 9854                    let mut bracket_pair = None;
 9855                    let max_lookup_length = scope
 9856                        .brackets()
 9857                        .map(|(pair, _)| {
 9858                            pair.start
 9859                                .as_str()
 9860                                .chars()
 9861                                .count()
 9862                                .max(pair.end.as_str().chars().count())
 9863                        })
 9864                        .max();
 9865                    if let Some(max_lookup_length) = max_lookup_length {
 9866                        let next_text = snapshot
 9867                            .chars_at(selection_head)
 9868                            .take(max_lookup_length)
 9869                            .collect::<String>();
 9870                        let prev_text = snapshot
 9871                            .reversed_chars_at(selection_head)
 9872                            .take(max_lookup_length)
 9873                            .collect::<String>();
 9874
 9875                        for (pair, enabled) in scope.brackets() {
 9876                            if enabled
 9877                                && pair.close
 9878                                && prev_text.starts_with(pair.start.as_str())
 9879                                && next_text.starts_with(pair.end.as_str())
 9880                            {
 9881                                bracket_pair = Some(pair.clone());
 9882                                break;
 9883                            }
 9884                        }
 9885                    }
 9886
 9887                    if let Some(pair) = bracket_pair {
 9888                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9889                        let autoclose_enabled =
 9890                            self.use_autoclose && snapshot_settings.use_autoclose;
 9891                        if autoclose_enabled {
 9892                            let start = snapshot.anchor_after(selection_head);
 9893                            let end = snapshot.anchor_after(selection_head);
 9894                            self.autoclose_regions.push(AutocloseRegion {
 9895                                selection_id: selection.id,
 9896                                range: start..end,
 9897                                pair,
 9898                            });
 9899                        }
 9900                    }
 9901                }
 9902            }
 9903        }
 9904        Ok(())
 9905    }
 9906
 9907    pub fn move_to_next_snippet_tabstop(
 9908        &mut self,
 9909        window: &mut Window,
 9910        cx: &mut Context<Self>,
 9911    ) -> bool {
 9912        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9913    }
 9914
 9915    pub fn move_to_prev_snippet_tabstop(
 9916        &mut self,
 9917        window: &mut Window,
 9918        cx: &mut Context<Self>,
 9919    ) -> bool {
 9920        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9921    }
 9922
 9923    pub fn move_to_snippet_tabstop(
 9924        &mut self,
 9925        bias: Bias,
 9926        window: &mut Window,
 9927        cx: &mut Context<Self>,
 9928    ) -> bool {
 9929        if let Some(mut snippet) = self.snippet_stack.pop() {
 9930            match bias {
 9931                Bias::Left => {
 9932                    if snippet.active_index > 0 {
 9933                        snippet.active_index -= 1;
 9934                    } else {
 9935                        self.snippet_stack.push(snippet);
 9936                        return false;
 9937                    }
 9938                }
 9939                Bias::Right => {
 9940                    if snippet.active_index + 1 < snippet.ranges.len() {
 9941                        snippet.active_index += 1;
 9942                    } else {
 9943                        self.snippet_stack.push(snippet);
 9944                        return false;
 9945                    }
 9946                }
 9947            }
 9948            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9949                self.change_selections(Default::default(), window, cx, |s| {
 9950                    // Reverse order so that the first range is the newest created selection.
 9951                    // Completions will use it and autoscroll will prioritize it.
 9952                    s.select_ranges(current_ranges.iter().rev().cloned())
 9953                });
 9954
 9955                if let Some(choices) = &snippet.choices[snippet.active_index]
 9956                    && let Some(selection) = current_ranges.first()
 9957                {
 9958                    self.show_snippet_choices(choices, selection.clone(), cx);
 9959                }
 9960
 9961                // If snippet state is not at the last tabstop, push it back on the stack
 9962                if snippet.active_index + 1 < snippet.ranges.len() {
 9963                    self.snippet_stack.push(snippet);
 9964                }
 9965                return true;
 9966            }
 9967        }
 9968
 9969        false
 9970    }
 9971
 9972    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9973        self.transact(window, cx, |this, window, cx| {
 9974            this.select_all(&SelectAll, window, cx);
 9975            this.insert("", window, cx);
 9976        });
 9977    }
 9978
 9979    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9980        if self.read_only(cx) {
 9981            return;
 9982        }
 9983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9984        self.transact(window, cx, |this, window, cx| {
 9985            this.select_autoclose_pair(window, cx);
 9986            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9987            if !this.linked_edit_ranges.is_empty() {
 9988                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9989                let snapshot = this.buffer.read(cx).snapshot(cx);
 9990
 9991                for selection in selections.iter() {
 9992                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9993                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9994                    if selection_start.buffer_id != selection_end.buffer_id {
 9995                        continue;
 9996                    }
 9997                    if let Some(ranges) =
 9998                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9999                    {
10000                        for (buffer, entries) in ranges {
10001                            linked_ranges.entry(buffer).or_default().extend(entries);
10002                        }
10003                    }
10004                }
10005            }
10006
10007            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10008            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10009            for selection in &mut selections {
10010                if selection.is_empty() {
10011                    let old_head = selection.head();
10012                    let mut new_head =
10013                        movement::left(&display_map, old_head.to_display_point(&display_map))
10014                            .to_point(&display_map);
10015                    if let Some((buffer, line_buffer_range)) = display_map
10016                        .buffer_snapshot()
10017                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10018                    {
10019                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10020                        let indent_len = match indent_size.kind {
10021                            IndentKind::Space => {
10022                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10023                            }
10024                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10025                        };
10026                        if old_head.column <= indent_size.len && old_head.column > 0 {
10027                            let indent_len = indent_len.get();
10028                            new_head = cmp::min(
10029                                new_head,
10030                                MultiBufferPoint::new(
10031                                    old_head.row,
10032                                    ((old_head.column - 1) / indent_len) * indent_len,
10033                                ),
10034                            );
10035                        }
10036                    }
10037
10038                    selection.set_head(new_head, SelectionGoal::None);
10039                }
10040            }
10041
10042            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10043            this.insert("", window, cx);
10044            let empty_str: Arc<str> = Arc::from("");
10045            for (buffer, edits) in linked_ranges {
10046                let snapshot = buffer.read(cx).snapshot();
10047                use text::ToPoint as TP;
10048
10049                let edits = edits
10050                    .into_iter()
10051                    .map(|range| {
10052                        let end_point = TP::to_point(&range.end, &snapshot);
10053                        let mut start_point = TP::to_point(&range.start, &snapshot);
10054
10055                        if end_point == start_point {
10056                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10057                                .saturating_sub(1);
10058                            start_point =
10059                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10060                        };
10061
10062                        (start_point..end_point, empty_str.clone())
10063                    })
10064                    .sorted_by_key(|(range, _)| range.start)
10065                    .collect::<Vec<_>>();
10066                buffer.update(cx, |this, cx| {
10067                    this.edit(edits, None, cx);
10068                })
10069            }
10070            this.refresh_edit_prediction(true, false, window, cx);
10071            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10072        });
10073    }
10074
10075    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10076        if self.read_only(cx) {
10077            return;
10078        }
10079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10080        self.transact(window, cx, |this, window, cx| {
10081            this.change_selections(Default::default(), window, cx, |s| {
10082                s.move_with(|map, selection| {
10083                    if selection.is_empty() {
10084                        let cursor = movement::right(map, selection.head());
10085                        selection.end = cursor;
10086                        selection.reversed = true;
10087                        selection.goal = SelectionGoal::None;
10088                    }
10089                })
10090            });
10091            this.insert("", window, cx);
10092            this.refresh_edit_prediction(true, false, window, cx);
10093        });
10094    }
10095
10096    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10097        if self.mode.is_single_line() {
10098            cx.propagate();
10099            return;
10100        }
10101
10102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10103        if self.move_to_prev_snippet_tabstop(window, cx) {
10104            return;
10105        }
10106        self.outdent(&Outdent, window, cx);
10107    }
10108
10109    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        if self.move_to_next_snippet_tabstop(window, cx) {
10116            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10117            return;
10118        }
10119        if self.read_only(cx) {
10120            return;
10121        }
10122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10123        let mut selections = self.selections.all_adjusted(cx);
10124        let buffer = self.buffer.read(cx);
10125        let snapshot = buffer.snapshot(cx);
10126        let rows_iter = selections.iter().map(|s| s.head().row);
10127        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10128
10129        let has_some_cursor_in_whitespace = selections
10130            .iter()
10131            .filter(|selection| selection.is_empty())
10132            .any(|selection| {
10133                let cursor = selection.head();
10134                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10135                cursor.column < current_indent.len
10136            });
10137
10138        let mut edits = Vec::new();
10139        let mut prev_edited_row = 0;
10140        let mut row_delta = 0;
10141        for selection in &mut selections {
10142            if selection.start.row != prev_edited_row {
10143                row_delta = 0;
10144            }
10145            prev_edited_row = selection.end.row;
10146
10147            // If the selection is non-empty, then increase the indentation of the selected lines.
10148            if !selection.is_empty() {
10149                row_delta =
10150                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10151                continue;
10152            }
10153
10154            let cursor = selection.head();
10155            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10156            if let Some(suggested_indent) =
10157                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10158            {
10159                // Don't do anything if already at suggested indent
10160                // and there is any other cursor which is not
10161                if has_some_cursor_in_whitespace
10162                    && cursor.column == current_indent.len
10163                    && current_indent.len == suggested_indent.len
10164                {
10165                    continue;
10166                }
10167
10168                // Adjust line and move cursor to suggested indent
10169                // if cursor is not at suggested indent
10170                if cursor.column < suggested_indent.len
10171                    && cursor.column <= current_indent.len
10172                    && current_indent.len <= suggested_indent.len
10173                {
10174                    selection.start = Point::new(cursor.row, suggested_indent.len);
10175                    selection.end = selection.start;
10176                    if row_delta == 0 {
10177                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10178                            cursor.row,
10179                            current_indent,
10180                            suggested_indent,
10181                        ));
10182                        row_delta = suggested_indent.len - current_indent.len;
10183                    }
10184                    continue;
10185                }
10186
10187                // If current indent is more than suggested indent
10188                // only move cursor to current indent and skip indent
10189                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10190                    selection.start = Point::new(cursor.row, current_indent.len);
10191                    selection.end = selection.start;
10192                    continue;
10193                }
10194            }
10195
10196            // Otherwise, insert a hard or soft tab.
10197            let settings = buffer.language_settings_at(cursor, cx);
10198            let tab_size = if settings.hard_tabs {
10199                IndentSize::tab()
10200            } else {
10201                let tab_size = settings.tab_size.get();
10202                let indent_remainder = snapshot
10203                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10204                    .flat_map(str::chars)
10205                    .fold(row_delta % tab_size, |counter: u32, c| {
10206                        if c == '\t' {
10207                            0
10208                        } else {
10209                            (counter + 1) % tab_size
10210                        }
10211                    });
10212
10213                let chars_to_next_tab_stop = tab_size - indent_remainder;
10214                IndentSize::spaces(chars_to_next_tab_stop)
10215            };
10216            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10217            selection.end = selection.start;
10218            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10219            row_delta += tab_size.len;
10220        }
10221
10222        self.transact(window, cx, |this, window, cx| {
10223            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10224            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10225            this.refresh_edit_prediction(true, false, window, cx);
10226        });
10227    }
10228
10229    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10230        if self.read_only(cx) {
10231            return;
10232        }
10233        if self.mode.is_single_line() {
10234            cx.propagate();
10235            return;
10236        }
10237
10238        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10239        let mut selections = self.selections.all::<Point>(cx);
10240        let mut prev_edited_row = 0;
10241        let mut row_delta = 0;
10242        let mut edits = Vec::new();
10243        let buffer = self.buffer.read(cx);
10244        let snapshot = buffer.snapshot(cx);
10245        for selection in &mut selections {
10246            if selection.start.row != prev_edited_row {
10247                row_delta = 0;
10248            }
10249            prev_edited_row = selection.end.row;
10250
10251            row_delta =
10252                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10253        }
10254
10255        self.transact(window, cx, |this, window, cx| {
10256            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10257            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10258        });
10259    }
10260
10261    fn indent_selection(
10262        buffer: &MultiBuffer,
10263        snapshot: &MultiBufferSnapshot,
10264        selection: &mut Selection<Point>,
10265        edits: &mut Vec<(Range<Point>, String)>,
10266        delta_for_start_row: u32,
10267        cx: &App,
10268    ) -> u32 {
10269        let settings = buffer.language_settings_at(selection.start, cx);
10270        let tab_size = settings.tab_size.get();
10271        let indent_kind = if settings.hard_tabs {
10272            IndentKind::Tab
10273        } else {
10274            IndentKind::Space
10275        };
10276        let mut start_row = selection.start.row;
10277        let mut end_row = selection.end.row + 1;
10278
10279        // If a selection ends at the beginning of a line, don't indent
10280        // that last line.
10281        if selection.end.column == 0 && selection.end.row > selection.start.row {
10282            end_row -= 1;
10283        }
10284
10285        // Avoid re-indenting a row that has already been indented by a
10286        // previous selection, but still update this selection's column
10287        // to reflect that indentation.
10288        if delta_for_start_row > 0 {
10289            start_row += 1;
10290            selection.start.column += delta_for_start_row;
10291            if selection.end.row == selection.start.row {
10292                selection.end.column += delta_for_start_row;
10293            }
10294        }
10295
10296        let mut delta_for_end_row = 0;
10297        let has_multiple_rows = start_row + 1 != end_row;
10298        for row in start_row..end_row {
10299            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10300            let indent_delta = match (current_indent.kind, indent_kind) {
10301                (IndentKind::Space, IndentKind::Space) => {
10302                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10303                    IndentSize::spaces(columns_to_next_tab_stop)
10304                }
10305                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10306                (_, IndentKind::Tab) => IndentSize::tab(),
10307            };
10308
10309            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10310                0
10311            } else {
10312                selection.start.column
10313            };
10314            let row_start = Point::new(row, start);
10315            edits.push((
10316                row_start..row_start,
10317                indent_delta.chars().collect::<String>(),
10318            ));
10319
10320            // Update this selection's endpoints to reflect the indentation.
10321            if row == selection.start.row {
10322                selection.start.column += indent_delta.len;
10323            }
10324            if row == selection.end.row {
10325                selection.end.column += indent_delta.len;
10326                delta_for_end_row = indent_delta.len;
10327            }
10328        }
10329
10330        if selection.start.row == selection.end.row {
10331            delta_for_start_row + delta_for_end_row
10332        } else {
10333            delta_for_end_row
10334        }
10335    }
10336
10337    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10338        if self.read_only(cx) {
10339            return;
10340        }
10341        if self.mode.is_single_line() {
10342            cx.propagate();
10343            return;
10344        }
10345
10346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10348        let selections = self.selections.all::<Point>(cx);
10349        let mut deletion_ranges = Vec::new();
10350        let mut last_outdent = None;
10351        {
10352            let buffer = self.buffer.read(cx);
10353            let snapshot = buffer.snapshot(cx);
10354            for selection in &selections {
10355                let settings = buffer.language_settings_at(selection.start, cx);
10356                let tab_size = settings.tab_size.get();
10357                let mut rows = selection.spanned_rows(false, &display_map);
10358
10359                // Avoid re-outdenting a row that has already been outdented by a
10360                // previous selection.
10361                if let Some(last_row) = last_outdent
10362                    && last_row == rows.start
10363                {
10364                    rows.start = rows.start.next_row();
10365                }
10366                let has_multiple_rows = rows.len() > 1;
10367                for row in rows.iter_rows() {
10368                    let indent_size = snapshot.indent_size_for_line(row);
10369                    if indent_size.len > 0 {
10370                        let deletion_len = match indent_size.kind {
10371                            IndentKind::Space => {
10372                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10373                                if columns_to_prev_tab_stop == 0 {
10374                                    tab_size
10375                                } else {
10376                                    columns_to_prev_tab_stop
10377                                }
10378                            }
10379                            IndentKind::Tab => 1,
10380                        };
10381                        let start = if has_multiple_rows
10382                            || deletion_len > selection.start.column
10383                            || indent_size.len < selection.start.column
10384                        {
10385                            0
10386                        } else {
10387                            selection.start.column - deletion_len
10388                        };
10389                        deletion_ranges.push(
10390                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10391                        );
10392                        last_outdent = Some(row);
10393                    }
10394                }
10395            }
10396        }
10397
10398        self.transact(window, cx, |this, window, cx| {
10399            this.buffer.update(cx, |buffer, cx| {
10400                let empty_str: Arc<str> = Arc::default();
10401                buffer.edit(
10402                    deletion_ranges
10403                        .into_iter()
10404                        .map(|range| (range, empty_str.clone())),
10405                    None,
10406                    cx,
10407                );
10408            });
10409            let selections = this.selections.all::<usize>(cx);
10410            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10411        });
10412    }
10413
10414    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10415        if self.read_only(cx) {
10416            return;
10417        }
10418        if self.mode.is_single_line() {
10419            cx.propagate();
10420            return;
10421        }
10422
10423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10424        let selections = self
10425            .selections
10426            .all::<usize>(cx)
10427            .into_iter()
10428            .map(|s| s.range());
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            this.buffer.update(cx, |buffer, cx| {
10432                buffer.autoindent_ranges(selections, cx);
10433            });
10434            let selections = this.selections.all::<usize>(cx);
10435            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10436        });
10437    }
10438
10439    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10442        let selections = self.selections.all::<Point>(cx);
10443
10444        let mut new_cursors = Vec::new();
10445        let mut edit_ranges = Vec::new();
10446        let mut selections = selections.iter().peekable();
10447        while let Some(selection) = selections.next() {
10448            let mut rows = selection.spanned_rows(false, &display_map);
10449
10450            // Accumulate contiguous regions of rows that we want to delete.
10451            while let Some(next_selection) = selections.peek() {
10452                let next_rows = next_selection.spanned_rows(false, &display_map);
10453                if next_rows.start <= rows.end {
10454                    rows.end = next_rows.end;
10455                    selections.next().unwrap();
10456                } else {
10457                    break;
10458                }
10459            }
10460
10461            let buffer = display_map.buffer_snapshot();
10462            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10463            let edit_end = if buffer.max_point().row >= rows.end.0 {
10464                // If there's a line after the range, delete the \n from the end of the row range
10465                ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer)
10466            } else {
10467                // If there isn't a line after the range, delete the \n from the line before the
10468                // start of the row range
10469                edit_start = edit_start.saturating_sub(1);
10470                buffer.len()
10471            };
10472
10473            let (cursor, goal) = movement::down_by_rows(
10474                &display_map,
10475                selection.head().to_display_point(&display_map),
10476                rows.len() as u32,
10477                selection.goal,
10478                false,
10479                &self.text_layout_details(window),
10480            );
10481
10482            new_cursors.push((
10483                selection.id,
10484                buffer.anchor_after(cursor.to_point(&display_map)),
10485                goal,
10486            ));
10487            edit_ranges.push(edit_start..edit_end);
10488        }
10489
10490        self.transact(window, cx, |this, window, cx| {
10491            let buffer = this.buffer.update(cx, |buffer, cx| {
10492                let empty_str: Arc<str> = Arc::default();
10493                buffer.edit(
10494                    edit_ranges
10495                        .into_iter()
10496                        .map(|range| (range, empty_str.clone())),
10497                    None,
10498                    cx,
10499                );
10500                buffer.snapshot(cx)
10501            });
10502            let new_selections = new_cursors
10503                .into_iter()
10504                .map(|(id, cursor, goal)| {
10505                    let cursor = cursor.to_point(&buffer);
10506                    Selection {
10507                        id,
10508                        start: cursor,
10509                        end: cursor,
10510                        reversed: false,
10511                        goal,
10512                    }
10513                })
10514                .collect();
10515
10516            this.change_selections(Default::default(), window, cx, |s| {
10517                s.select(new_selections);
10518            });
10519        });
10520    }
10521
10522    pub fn join_lines_impl(
10523        &mut self,
10524        insert_whitespace: bool,
10525        window: &mut Window,
10526        cx: &mut Context<Self>,
10527    ) {
10528        if self.read_only(cx) {
10529            return;
10530        }
10531        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10532        for selection in self.selections.all::<Point>(cx) {
10533            let start = MultiBufferRow(selection.start.row);
10534            // Treat single line selections as if they include the next line. Otherwise this action
10535            // would do nothing for single line selections individual cursors.
10536            let end = if selection.start.row == selection.end.row {
10537                MultiBufferRow(selection.start.row + 1)
10538            } else {
10539                MultiBufferRow(selection.end.row)
10540            };
10541
10542            if let Some(last_row_range) = row_ranges.last_mut()
10543                && start <= last_row_range.end
10544            {
10545                last_row_range.end = end;
10546                continue;
10547            }
10548            row_ranges.push(start..end);
10549        }
10550
10551        let snapshot = self.buffer.read(cx).snapshot(cx);
10552        let mut cursor_positions = Vec::new();
10553        for row_range in &row_ranges {
10554            let anchor = snapshot.anchor_before(Point::new(
10555                row_range.end.previous_row().0,
10556                snapshot.line_len(row_range.end.previous_row()),
10557            ));
10558            cursor_positions.push(anchor..anchor);
10559        }
10560
10561        self.transact(window, cx, |this, window, cx| {
10562            for row_range in row_ranges.into_iter().rev() {
10563                for row in row_range.iter_rows().rev() {
10564                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10565                    let next_line_row = row.next_row();
10566                    let indent = snapshot.indent_size_for_line(next_line_row);
10567                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10568
10569                    let replace =
10570                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10571                            " "
10572                        } else {
10573                            ""
10574                        };
10575
10576                    this.buffer.update(cx, |buffer, cx| {
10577                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10578                    });
10579                }
10580            }
10581
10582            this.change_selections(Default::default(), window, cx, |s| {
10583                s.select_anchor_ranges(cursor_positions)
10584            });
10585        });
10586    }
10587
10588    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10590        self.join_lines_impl(true, window, cx);
10591    }
10592
10593    pub fn sort_lines_case_sensitive(
10594        &mut self,
10595        _: &SortLinesCaseSensitive,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10600    }
10601
10602    pub fn sort_lines_by_length(
10603        &mut self,
10604        _: &SortLinesByLength,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.manipulate_immutable_lines(window, cx, |lines| {
10609            lines.sort_by_key(|&line| line.chars().count())
10610        })
10611    }
10612
10613    pub fn sort_lines_case_insensitive(
10614        &mut self,
10615        _: &SortLinesCaseInsensitive,
10616        window: &mut Window,
10617        cx: &mut Context<Self>,
10618    ) {
10619        self.manipulate_immutable_lines(window, cx, |lines| {
10620            lines.sort_by_key(|line| line.to_lowercase())
10621        })
10622    }
10623
10624    pub fn unique_lines_case_insensitive(
10625        &mut self,
10626        _: &UniqueLinesCaseInsensitive,
10627        window: &mut Window,
10628        cx: &mut Context<Self>,
10629    ) {
10630        self.manipulate_immutable_lines(window, cx, |lines| {
10631            let mut seen = HashSet::default();
10632            lines.retain(|line| seen.insert(line.to_lowercase()));
10633        })
10634    }
10635
10636    pub fn unique_lines_case_sensitive(
10637        &mut self,
10638        _: &UniqueLinesCaseSensitive,
10639        window: &mut Window,
10640        cx: &mut Context<Self>,
10641    ) {
10642        self.manipulate_immutable_lines(window, cx, |lines| {
10643            let mut seen = HashSet::default();
10644            lines.retain(|line| seen.insert(*line));
10645        })
10646    }
10647
10648    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10649        let snapshot = self.buffer.read(cx).snapshot(cx);
10650        for selection in self.selections.disjoint_anchors_arc().iter() {
10651            if snapshot
10652                .language_at(selection.start)
10653                .and_then(|lang| lang.config().wrap_characters.as_ref())
10654                .is_some()
10655            {
10656                return true;
10657            }
10658        }
10659        false
10660    }
10661
10662    fn wrap_selections_in_tag(
10663        &mut self,
10664        _: &WrapSelectionsInTag,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10669
10670        let snapshot = self.buffer.read(cx).snapshot(cx);
10671
10672        let mut edits = Vec::new();
10673        let mut boundaries = Vec::new();
10674
10675        for selection in self.selections.all::<Point>(cx).iter() {
10676            let Some(wrap_config) = snapshot
10677                .language_at(selection.start)
10678                .and_then(|lang| lang.config().wrap_characters.clone())
10679            else {
10680                continue;
10681            };
10682
10683            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10684            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10685
10686            let start_before = snapshot.anchor_before(selection.start);
10687            let end_after = snapshot.anchor_after(selection.end);
10688
10689            edits.push((start_before..start_before, open_tag));
10690            edits.push((end_after..end_after, close_tag));
10691
10692            boundaries.push((
10693                start_before,
10694                end_after,
10695                wrap_config.start_prefix.len(),
10696                wrap_config.end_suffix.len(),
10697            ));
10698        }
10699
10700        if edits.is_empty() {
10701            return;
10702        }
10703
10704        self.transact(window, cx, |this, window, cx| {
10705            let buffer = this.buffer.update(cx, |buffer, cx| {
10706                buffer.edit(edits, None, cx);
10707                buffer.snapshot(cx)
10708            });
10709
10710            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10711            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10712                boundaries.into_iter()
10713            {
10714                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10715                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10716                new_selections.push(open_offset..open_offset);
10717                new_selections.push(close_offset..close_offset);
10718            }
10719
10720            this.change_selections(Default::default(), window, cx, |s| {
10721                s.select_ranges(new_selections);
10722            });
10723
10724            this.request_autoscroll(Autoscroll::fit(), cx);
10725        });
10726    }
10727
10728    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10729        let Some(project) = self.project.clone() else {
10730            return;
10731        };
10732        self.reload(project, window, cx)
10733            .detach_and_notify_err(window, cx);
10734    }
10735
10736    pub fn restore_file(
10737        &mut self,
10738        _: &::git::RestoreFile,
10739        window: &mut Window,
10740        cx: &mut Context<Self>,
10741    ) {
10742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10743        let mut buffer_ids = HashSet::default();
10744        let snapshot = self.buffer().read(cx).snapshot(cx);
10745        for selection in self.selections.all::<usize>(cx) {
10746            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10747        }
10748
10749        let buffer = self.buffer().read(cx);
10750        let ranges = buffer_ids
10751            .into_iter()
10752            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10753            .collect::<Vec<_>>();
10754
10755        self.restore_hunks_in_ranges(ranges, window, cx);
10756    }
10757
10758    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10760        let selections = self
10761            .selections
10762            .all(cx)
10763            .into_iter()
10764            .map(|s| s.range())
10765            .collect();
10766        self.restore_hunks_in_ranges(selections, window, cx);
10767    }
10768
10769    pub fn restore_hunks_in_ranges(
10770        &mut self,
10771        ranges: Vec<Range<Point>>,
10772        window: &mut Window,
10773        cx: &mut Context<Editor>,
10774    ) {
10775        let mut revert_changes = HashMap::default();
10776        let chunk_by = self
10777            .snapshot(window, cx)
10778            .hunks_for_ranges(ranges)
10779            .into_iter()
10780            .chunk_by(|hunk| hunk.buffer_id);
10781        for (buffer_id, hunks) in &chunk_by {
10782            let hunks = hunks.collect::<Vec<_>>();
10783            for hunk in &hunks {
10784                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10785            }
10786            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10787        }
10788        drop(chunk_by);
10789        if !revert_changes.is_empty() {
10790            self.transact(window, cx, |editor, window, cx| {
10791                editor.restore(revert_changes, window, cx);
10792            });
10793        }
10794    }
10795
10796    pub fn open_active_item_in_terminal(
10797        &mut self,
10798        _: &OpenInTerminal,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) {
10802        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10803            let project_path = buffer.read(cx).project_path(cx)?;
10804            let project = self.project()?.read(cx);
10805            let entry = project.entry_for_path(&project_path, cx)?;
10806            let parent = match &entry.canonical_path {
10807                Some(canonical_path) => canonical_path.to_path_buf(),
10808                None => project.absolute_path(&project_path, cx)?,
10809            }
10810            .parent()?
10811            .to_path_buf();
10812            Some(parent)
10813        }) {
10814            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10815        }
10816    }
10817
10818    fn set_breakpoint_context_menu(
10819        &mut self,
10820        display_row: DisplayRow,
10821        position: Option<Anchor>,
10822        clicked_point: gpui::Point<Pixels>,
10823        window: &mut Window,
10824        cx: &mut Context<Self>,
10825    ) {
10826        let source = self
10827            .buffer
10828            .read(cx)
10829            .snapshot(cx)
10830            .anchor_before(Point::new(display_row.0, 0u32));
10831
10832        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10833
10834        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10835            self,
10836            source,
10837            clicked_point,
10838            context_menu,
10839            window,
10840            cx,
10841        );
10842    }
10843
10844    fn add_edit_breakpoint_block(
10845        &mut self,
10846        anchor: Anchor,
10847        breakpoint: &Breakpoint,
10848        edit_action: BreakpointPromptEditAction,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851    ) {
10852        let weak_editor = cx.weak_entity();
10853        let bp_prompt = cx.new(|cx| {
10854            BreakpointPromptEditor::new(
10855                weak_editor,
10856                anchor,
10857                breakpoint.clone(),
10858                edit_action,
10859                window,
10860                cx,
10861            )
10862        });
10863
10864        let height = bp_prompt.update(cx, |this, cx| {
10865            this.prompt
10866                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10867        });
10868        let cloned_prompt = bp_prompt.clone();
10869        let blocks = vec![BlockProperties {
10870            style: BlockStyle::Sticky,
10871            placement: BlockPlacement::Above(anchor),
10872            height: Some(height),
10873            render: Arc::new(move |cx| {
10874                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10875                cloned_prompt.clone().into_any_element()
10876            }),
10877            priority: 0,
10878        }];
10879
10880        let focus_handle = bp_prompt.focus_handle(cx);
10881        window.focus(&focus_handle);
10882
10883        let block_ids = self.insert_blocks(blocks, None, cx);
10884        bp_prompt.update(cx, |prompt, _| {
10885            prompt.add_block_ids(block_ids);
10886        });
10887    }
10888
10889    pub(crate) fn breakpoint_at_row(
10890        &self,
10891        row: u32,
10892        window: &mut Window,
10893        cx: &mut Context<Self>,
10894    ) -> Option<(Anchor, Breakpoint)> {
10895        let snapshot = self.snapshot(window, cx);
10896        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10897
10898        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10899    }
10900
10901    pub(crate) fn breakpoint_at_anchor(
10902        &self,
10903        breakpoint_position: Anchor,
10904        snapshot: &EditorSnapshot,
10905        cx: &mut Context<Self>,
10906    ) -> Option<(Anchor, Breakpoint)> {
10907        let buffer = self
10908            .buffer
10909            .read(cx)
10910            .buffer_for_anchor(breakpoint_position, cx)?;
10911
10912        let enclosing_excerpt = breakpoint_position.excerpt_id;
10913        let buffer_snapshot = buffer.read(cx).snapshot();
10914
10915        let row = buffer_snapshot
10916            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10917            .row;
10918
10919        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10920        let anchor_end = snapshot
10921            .buffer_snapshot()
10922            .anchor_after(Point::new(row, line_len));
10923
10924        self.breakpoint_store
10925            .as_ref()?
10926            .read_with(cx, |breakpoint_store, cx| {
10927                breakpoint_store
10928                    .breakpoints(
10929                        &buffer,
10930                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10931                        &buffer_snapshot,
10932                        cx,
10933                    )
10934                    .next()
10935                    .and_then(|(bp, _)| {
10936                        let breakpoint_row = buffer_snapshot
10937                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10938                            .row;
10939
10940                        if breakpoint_row == row {
10941                            snapshot
10942                                .buffer_snapshot()
10943                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10944                                .map(|position| (position, bp.bp.clone()))
10945                        } else {
10946                            None
10947                        }
10948                    })
10949            })
10950    }
10951
10952    pub fn edit_log_breakpoint(
10953        &mut self,
10954        _: &EditLogBreakpoint,
10955        window: &mut Window,
10956        cx: &mut Context<Self>,
10957    ) {
10958        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10959            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10960                message: None,
10961                state: BreakpointState::Enabled,
10962                condition: None,
10963                hit_condition: None,
10964            });
10965
10966            self.add_edit_breakpoint_block(
10967                anchor,
10968                &breakpoint,
10969                BreakpointPromptEditAction::Log,
10970                window,
10971                cx,
10972            );
10973        }
10974    }
10975
10976    fn breakpoints_at_cursors(
10977        &self,
10978        window: &mut Window,
10979        cx: &mut Context<Self>,
10980    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10981        let snapshot = self.snapshot(window, cx);
10982        let cursors = self
10983            .selections
10984            .disjoint_anchors_arc()
10985            .iter()
10986            .map(|selection| {
10987                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10988
10989                let breakpoint_position = self
10990                    .breakpoint_at_row(cursor_position.row, window, cx)
10991                    .map(|bp| bp.0)
10992                    .unwrap_or_else(|| {
10993                        snapshot
10994                            .display_snapshot
10995                            .buffer_snapshot()
10996                            .anchor_after(Point::new(cursor_position.row, 0))
10997                    });
10998
10999                let breakpoint = self
11000                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11001                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11002
11003                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11004            })
11005            // 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.
11006            .collect::<HashMap<Anchor, _>>();
11007
11008        cursors.into_iter().collect()
11009    }
11010
11011    pub fn enable_breakpoint(
11012        &mut self,
11013        _: &crate::actions::EnableBreakpoint,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11018            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11019                continue;
11020            };
11021            self.edit_breakpoint_at_anchor(
11022                anchor,
11023                breakpoint,
11024                BreakpointEditAction::InvertState,
11025                cx,
11026            );
11027        }
11028    }
11029
11030    pub fn disable_breakpoint(
11031        &mut self,
11032        _: &crate::actions::DisableBreakpoint,
11033        window: &mut Window,
11034        cx: &mut Context<Self>,
11035    ) {
11036        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11037            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11038                continue;
11039            };
11040            self.edit_breakpoint_at_anchor(
11041                anchor,
11042                breakpoint,
11043                BreakpointEditAction::InvertState,
11044                cx,
11045            );
11046        }
11047    }
11048
11049    pub fn toggle_breakpoint(
11050        &mut self,
11051        _: &crate::actions::ToggleBreakpoint,
11052        window: &mut Window,
11053        cx: &mut Context<Self>,
11054    ) {
11055        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11056            if let Some(breakpoint) = breakpoint {
11057                self.edit_breakpoint_at_anchor(
11058                    anchor,
11059                    breakpoint,
11060                    BreakpointEditAction::Toggle,
11061                    cx,
11062                );
11063            } else {
11064                self.edit_breakpoint_at_anchor(
11065                    anchor,
11066                    Breakpoint::new_standard(),
11067                    BreakpointEditAction::Toggle,
11068                    cx,
11069                );
11070            }
11071        }
11072    }
11073
11074    pub fn edit_breakpoint_at_anchor(
11075        &mut self,
11076        breakpoint_position: Anchor,
11077        breakpoint: Breakpoint,
11078        edit_action: BreakpointEditAction,
11079        cx: &mut Context<Self>,
11080    ) {
11081        let Some(breakpoint_store) = &self.breakpoint_store else {
11082            return;
11083        };
11084
11085        let Some(buffer) = self
11086            .buffer
11087            .read(cx)
11088            .buffer_for_anchor(breakpoint_position, cx)
11089        else {
11090            return;
11091        };
11092
11093        breakpoint_store.update(cx, |breakpoint_store, cx| {
11094            breakpoint_store.toggle_breakpoint(
11095                buffer,
11096                BreakpointWithPosition {
11097                    position: breakpoint_position.text_anchor,
11098                    bp: breakpoint,
11099                },
11100                edit_action,
11101                cx,
11102            );
11103        });
11104
11105        cx.notify();
11106    }
11107
11108    #[cfg(any(test, feature = "test-support"))]
11109    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11110        self.breakpoint_store.clone()
11111    }
11112
11113    pub fn prepare_restore_change(
11114        &self,
11115        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11116        hunk: &MultiBufferDiffHunk,
11117        cx: &mut App,
11118    ) -> Option<()> {
11119        if hunk.is_created_file() {
11120            return None;
11121        }
11122        let buffer = self.buffer.read(cx);
11123        let diff = buffer.diff_for(hunk.buffer_id)?;
11124        let buffer = buffer.buffer(hunk.buffer_id)?;
11125        let buffer = buffer.read(cx);
11126        let original_text = diff
11127            .read(cx)
11128            .base_text()
11129            .as_rope()
11130            .slice(hunk.diff_base_byte_range.clone());
11131        let buffer_snapshot = buffer.snapshot();
11132        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11133        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11134            probe
11135                .0
11136                .start
11137                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11138                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11139        }) {
11140            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11141            Some(())
11142        } else {
11143            None
11144        }
11145    }
11146
11147    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11148        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11149    }
11150
11151    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11152        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11153    }
11154
11155    fn manipulate_lines<M>(
11156        &mut self,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159        mut manipulate: M,
11160    ) where
11161        M: FnMut(&str) -> LineManipulationResult,
11162    {
11163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11164
11165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11166        let buffer = self.buffer.read(cx).snapshot(cx);
11167
11168        let mut edits = Vec::new();
11169
11170        let selections = self.selections.all::<Point>(cx);
11171        let mut selections = selections.iter().peekable();
11172        let mut contiguous_row_selections = Vec::new();
11173        let mut new_selections = Vec::new();
11174        let mut added_lines = 0;
11175        let mut removed_lines = 0;
11176
11177        while let Some(selection) = selections.next() {
11178            let (start_row, end_row) = consume_contiguous_rows(
11179                &mut contiguous_row_selections,
11180                selection,
11181                &display_map,
11182                &mut selections,
11183            );
11184
11185            let start_point = Point::new(start_row.0, 0);
11186            let end_point = Point::new(
11187                end_row.previous_row().0,
11188                buffer.line_len(end_row.previous_row()),
11189            );
11190            let text = buffer
11191                .text_for_range(start_point..end_point)
11192                .collect::<String>();
11193
11194            let LineManipulationResult {
11195                new_text,
11196                line_count_before,
11197                line_count_after,
11198            } = manipulate(&text);
11199
11200            edits.push((start_point..end_point, new_text));
11201
11202            // Selections must change based on added and removed line count
11203            let start_row =
11204                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11205            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11206            new_selections.push(Selection {
11207                id: selection.id,
11208                start: start_row,
11209                end: end_row,
11210                goal: SelectionGoal::None,
11211                reversed: selection.reversed,
11212            });
11213
11214            if line_count_after > line_count_before {
11215                added_lines += line_count_after - line_count_before;
11216            } else if line_count_before > line_count_after {
11217                removed_lines += line_count_before - line_count_after;
11218            }
11219        }
11220
11221        self.transact(window, cx, |this, window, cx| {
11222            let buffer = this.buffer.update(cx, |buffer, cx| {
11223                buffer.edit(edits, None, cx);
11224                buffer.snapshot(cx)
11225            });
11226
11227            // Recalculate offsets on newly edited buffer
11228            let new_selections = new_selections
11229                .iter()
11230                .map(|s| {
11231                    let start_point = Point::new(s.start.0, 0);
11232                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11233                    Selection {
11234                        id: s.id,
11235                        start: buffer.point_to_offset(start_point),
11236                        end: buffer.point_to_offset(end_point),
11237                        goal: s.goal,
11238                        reversed: s.reversed,
11239                    }
11240                })
11241                .collect();
11242
11243            this.change_selections(Default::default(), window, cx, |s| {
11244                s.select(new_selections);
11245            });
11246
11247            this.request_autoscroll(Autoscroll::fit(), cx);
11248        });
11249    }
11250
11251    fn manipulate_immutable_lines<Fn>(
11252        &mut self,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255        mut callback: Fn,
11256    ) where
11257        Fn: FnMut(&mut Vec<&str>),
11258    {
11259        self.manipulate_lines(window, cx, |text| {
11260            let mut lines: Vec<&str> = text.split('\n').collect();
11261            let line_count_before = lines.len();
11262
11263            callback(&mut lines);
11264
11265            LineManipulationResult {
11266                new_text: lines.join("\n"),
11267                line_count_before,
11268                line_count_after: lines.len(),
11269            }
11270        });
11271    }
11272
11273    fn manipulate_mutable_lines<Fn>(
11274        &mut self,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277        mut callback: Fn,
11278    ) where
11279        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11280    {
11281        self.manipulate_lines(window, cx, |text| {
11282            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11283            let line_count_before = lines.len();
11284
11285            callback(&mut lines);
11286
11287            LineManipulationResult {
11288                new_text: lines.join("\n"),
11289                line_count_before,
11290                line_count_after: lines.len(),
11291            }
11292        });
11293    }
11294
11295    pub fn convert_indentation_to_spaces(
11296        &mut self,
11297        _: &ConvertIndentationToSpaces,
11298        window: &mut Window,
11299        cx: &mut Context<Self>,
11300    ) {
11301        let settings = self.buffer.read(cx).language_settings(cx);
11302        let tab_size = settings.tab_size.get() as usize;
11303
11304        self.manipulate_mutable_lines(window, cx, |lines| {
11305            // Allocates a reasonably sized scratch buffer once for the whole loop
11306            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11307            // Avoids recomputing spaces that could be inserted many times
11308            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11309                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11310                .collect();
11311
11312            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11313                let mut chars = line.as_ref().chars();
11314                let mut col = 0;
11315                let mut changed = false;
11316
11317                for ch in chars.by_ref() {
11318                    match ch {
11319                        ' ' => {
11320                            reindented_line.push(' ');
11321                            col += 1;
11322                        }
11323                        '\t' => {
11324                            // \t are converted to spaces depending on the current column
11325                            let spaces_len = tab_size - (col % tab_size);
11326                            reindented_line.extend(&space_cache[spaces_len - 1]);
11327                            col += spaces_len;
11328                            changed = true;
11329                        }
11330                        _ => {
11331                            // If we dont append before break, the character is consumed
11332                            reindented_line.push(ch);
11333                            break;
11334                        }
11335                    }
11336                }
11337
11338                if !changed {
11339                    reindented_line.clear();
11340                    continue;
11341                }
11342                // Append the rest of the line and replace old reference with new one
11343                reindented_line.extend(chars);
11344                *line = Cow::Owned(reindented_line.clone());
11345                reindented_line.clear();
11346            }
11347        });
11348    }
11349
11350    pub fn convert_indentation_to_tabs(
11351        &mut self,
11352        _: &ConvertIndentationToTabs,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        let settings = self.buffer.read(cx).language_settings(cx);
11357        let tab_size = settings.tab_size.get() as usize;
11358
11359        self.manipulate_mutable_lines(window, cx, |lines| {
11360            // Allocates a reasonably sized buffer once for the whole loop
11361            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11362            // Avoids recomputing spaces that could be inserted many times
11363            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11364                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11365                .collect();
11366
11367            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11368                let mut chars = line.chars();
11369                let mut spaces_count = 0;
11370                let mut first_non_indent_char = None;
11371                let mut changed = false;
11372
11373                for ch in chars.by_ref() {
11374                    match ch {
11375                        ' ' => {
11376                            // Keep track of spaces. Append \t when we reach tab_size
11377                            spaces_count += 1;
11378                            changed = true;
11379                            if spaces_count == tab_size {
11380                                reindented_line.push('\t');
11381                                spaces_count = 0;
11382                            }
11383                        }
11384                        '\t' => {
11385                            reindented_line.push('\t');
11386                            spaces_count = 0;
11387                        }
11388                        _ => {
11389                            // Dont append it yet, we might have remaining spaces
11390                            first_non_indent_char = Some(ch);
11391                            break;
11392                        }
11393                    }
11394                }
11395
11396                if !changed {
11397                    reindented_line.clear();
11398                    continue;
11399                }
11400                // Remaining spaces that didn't make a full tab stop
11401                if spaces_count > 0 {
11402                    reindented_line.extend(&space_cache[spaces_count - 1]);
11403                }
11404                // If we consume an extra character that was not indentation, add it back
11405                if let Some(extra_char) = first_non_indent_char {
11406                    reindented_line.push(extra_char);
11407                }
11408                // Append the rest of the line and replace old reference with new one
11409                reindented_line.extend(chars);
11410                *line = Cow::Owned(reindented_line.clone());
11411                reindented_line.clear();
11412            }
11413        });
11414    }
11415
11416    pub fn convert_to_upper_case(
11417        &mut self,
11418        _: &ConvertToUpperCase,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        self.manipulate_text(window, cx, |text| text.to_uppercase())
11423    }
11424
11425    pub fn convert_to_lower_case(
11426        &mut self,
11427        _: &ConvertToLowerCase,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        self.manipulate_text(window, cx, |text| text.to_lowercase())
11432    }
11433
11434    pub fn convert_to_title_case(
11435        &mut self,
11436        _: &ConvertToTitleCase,
11437        window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        self.manipulate_text(window, cx, |text| {
11441            text.split('\n')
11442                .map(|line| line.to_case(Case::Title))
11443                .join("\n")
11444        })
11445    }
11446
11447    pub fn convert_to_snake_case(
11448        &mut self,
11449        _: &ConvertToSnakeCase,
11450        window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11454    }
11455
11456    pub fn convert_to_kebab_case(
11457        &mut self,
11458        _: &ConvertToKebabCase,
11459        window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11463    }
11464
11465    pub fn convert_to_upper_camel_case(
11466        &mut self,
11467        _: &ConvertToUpperCamelCase,
11468        window: &mut Window,
11469        cx: &mut Context<Self>,
11470    ) {
11471        self.manipulate_text(window, cx, |text| {
11472            text.split('\n')
11473                .map(|line| line.to_case(Case::UpperCamel))
11474                .join("\n")
11475        })
11476    }
11477
11478    pub fn convert_to_lower_camel_case(
11479        &mut self,
11480        _: &ConvertToLowerCamelCase,
11481        window: &mut Window,
11482        cx: &mut Context<Self>,
11483    ) {
11484        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11485    }
11486
11487    pub fn convert_to_opposite_case(
11488        &mut self,
11489        _: &ConvertToOppositeCase,
11490        window: &mut Window,
11491        cx: &mut Context<Self>,
11492    ) {
11493        self.manipulate_text(window, cx, |text| {
11494            text.chars()
11495                .fold(String::with_capacity(text.len()), |mut t, c| {
11496                    if c.is_uppercase() {
11497                        t.extend(c.to_lowercase());
11498                    } else {
11499                        t.extend(c.to_uppercase());
11500                    }
11501                    t
11502                })
11503        })
11504    }
11505
11506    pub fn convert_to_sentence_case(
11507        &mut self,
11508        _: &ConvertToSentenceCase,
11509        window: &mut Window,
11510        cx: &mut Context<Self>,
11511    ) {
11512        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11513    }
11514
11515    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11516        self.manipulate_text(window, cx, |text| {
11517            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11518            if has_upper_case_characters {
11519                text.to_lowercase()
11520            } else {
11521                text.to_uppercase()
11522            }
11523        })
11524    }
11525
11526    pub fn convert_to_rot13(
11527        &mut self,
11528        _: &ConvertToRot13,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) {
11532        self.manipulate_text(window, cx, |text| {
11533            text.chars()
11534                .map(|c| match c {
11535                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11536                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11537                    _ => c,
11538                })
11539                .collect()
11540        })
11541    }
11542
11543    pub fn convert_to_rot47(
11544        &mut self,
11545        _: &ConvertToRot47,
11546        window: &mut Window,
11547        cx: &mut Context<Self>,
11548    ) {
11549        self.manipulate_text(window, cx, |text| {
11550            text.chars()
11551                .map(|c| {
11552                    let code_point = c as u32;
11553                    if code_point >= 33 && code_point <= 126 {
11554                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11555                    }
11556                    c
11557                })
11558                .collect()
11559        })
11560    }
11561
11562    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11563    where
11564        Fn: FnMut(&str) -> String,
11565    {
11566        let buffer = self.buffer.read(cx).snapshot(cx);
11567
11568        let mut new_selections = Vec::new();
11569        let mut edits = Vec::new();
11570        let mut selection_adjustment = 0i32;
11571
11572        for selection in self.selections.all_adjusted(cx) {
11573            let selection_is_empty = selection.is_empty();
11574
11575            let (start, end) = if selection_is_empty {
11576                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11577                (word_range.start, word_range.end)
11578            } else {
11579                (
11580                    buffer.point_to_offset(selection.start),
11581                    buffer.point_to_offset(selection.end),
11582                )
11583            };
11584
11585            let text = buffer.text_for_range(start..end).collect::<String>();
11586            let old_length = text.len() as i32;
11587            let text = callback(&text);
11588
11589            new_selections.push(Selection {
11590                start: (start as i32 - selection_adjustment) as usize,
11591                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11592                goal: SelectionGoal::None,
11593                id: selection.id,
11594                reversed: selection.reversed,
11595            });
11596
11597            selection_adjustment += old_length - text.len() as i32;
11598
11599            edits.push((start..end, text));
11600        }
11601
11602        self.transact(window, cx, |this, window, cx| {
11603            this.buffer.update(cx, |buffer, cx| {
11604                buffer.edit(edits, None, cx);
11605            });
11606
11607            this.change_selections(Default::default(), window, cx, |s| {
11608                s.select(new_selections);
11609            });
11610
11611            this.request_autoscroll(Autoscroll::fit(), cx);
11612        });
11613    }
11614
11615    pub fn move_selection_on_drop(
11616        &mut self,
11617        selection: &Selection<Anchor>,
11618        target: DisplayPoint,
11619        is_cut: bool,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11624        let buffer = display_map.buffer_snapshot();
11625        let mut edits = Vec::new();
11626        let insert_point = display_map
11627            .clip_point(target, Bias::Left)
11628            .to_point(&display_map);
11629        let text = buffer
11630            .text_for_range(selection.start..selection.end)
11631            .collect::<String>();
11632        if is_cut {
11633            edits.push(((selection.start..selection.end), String::new()));
11634        }
11635        let insert_anchor = buffer.anchor_before(insert_point);
11636        edits.push(((insert_anchor..insert_anchor), text));
11637        let last_edit_start = insert_anchor.bias_left(buffer);
11638        let last_edit_end = insert_anchor.bias_right(buffer);
11639        self.transact(window, cx, |this, window, cx| {
11640            this.buffer.update(cx, |buffer, cx| {
11641                buffer.edit(edits, None, cx);
11642            });
11643            this.change_selections(Default::default(), window, cx, |s| {
11644                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11645            });
11646        });
11647    }
11648
11649    pub fn clear_selection_drag_state(&mut self) {
11650        self.selection_drag_state = SelectionDragState::None;
11651    }
11652
11653    pub fn duplicate(
11654        &mut self,
11655        upwards: bool,
11656        whole_lines: bool,
11657        window: &mut Window,
11658        cx: &mut Context<Self>,
11659    ) {
11660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11661
11662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11663        let buffer = display_map.buffer_snapshot();
11664        let selections = self.selections.all::<Point>(cx);
11665
11666        let mut edits = Vec::new();
11667        let mut selections_iter = selections.iter().peekable();
11668        while let Some(selection) = selections_iter.next() {
11669            let mut rows = selection.spanned_rows(false, &display_map);
11670            // duplicate line-wise
11671            if whole_lines || selection.start == selection.end {
11672                // Avoid duplicating the same lines twice.
11673                while let Some(next_selection) = selections_iter.peek() {
11674                    let next_rows = next_selection.spanned_rows(false, &display_map);
11675                    if next_rows.start < rows.end {
11676                        rows.end = next_rows.end;
11677                        selections_iter.next().unwrap();
11678                    } else {
11679                        break;
11680                    }
11681                }
11682
11683                // Copy the text from the selected row region and splice it either at the start
11684                // or end of the region.
11685                let start = Point::new(rows.start.0, 0);
11686                let end = Point::new(
11687                    rows.end.previous_row().0,
11688                    buffer.line_len(rows.end.previous_row()),
11689                );
11690                let text = buffer
11691                    .text_for_range(start..end)
11692                    .chain(Some("\n"))
11693                    .collect::<String>();
11694                let insert_location = if upwards {
11695                    Point::new(rows.end.0, 0)
11696                } else {
11697                    start
11698                };
11699                edits.push((insert_location..insert_location, text));
11700            } else {
11701                // duplicate character-wise
11702                let start = selection.start;
11703                let end = selection.end;
11704                let text = buffer.text_for_range(start..end).collect::<String>();
11705                edits.push((selection.end..selection.end, text));
11706            }
11707        }
11708
11709        self.transact(window, cx, |this, _, cx| {
11710            this.buffer.update(cx, |buffer, cx| {
11711                buffer.edit(edits, None, cx);
11712            });
11713
11714            this.request_autoscroll(Autoscroll::fit(), cx);
11715        });
11716    }
11717
11718    pub fn duplicate_line_up(
11719        &mut self,
11720        _: &DuplicateLineUp,
11721        window: &mut Window,
11722        cx: &mut Context<Self>,
11723    ) {
11724        self.duplicate(true, true, window, cx);
11725    }
11726
11727    pub fn duplicate_line_down(
11728        &mut self,
11729        _: &DuplicateLineDown,
11730        window: &mut Window,
11731        cx: &mut Context<Self>,
11732    ) {
11733        self.duplicate(false, true, window, cx);
11734    }
11735
11736    pub fn duplicate_selection(
11737        &mut self,
11738        _: &DuplicateSelection,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        self.duplicate(false, false, window, cx);
11743    }
11744
11745    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11746        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11747        if self.mode.is_single_line() {
11748            cx.propagate();
11749            return;
11750        }
11751
11752        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11753        let buffer = self.buffer.read(cx).snapshot(cx);
11754
11755        let mut edits = Vec::new();
11756        let mut unfold_ranges = Vec::new();
11757        let mut refold_creases = Vec::new();
11758
11759        let selections = self.selections.all::<Point>(cx);
11760        let mut selections = selections.iter().peekable();
11761        let mut contiguous_row_selections = Vec::new();
11762        let mut new_selections = Vec::new();
11763
11764        while let Some(selection) = selections.next() {
11765            // Find all the selections that span a contiguous row range
11766            let (start_row, end_row) = consume_contiguous_rows(
11767                &mut contiguous_row_selections,
11768                selection,
11769                &display_map,
11770                &mut selections,
11771            );
11772
11773            // Move the text spanned by the row range to be before the line preceding the row range
11774            if start_row.0 > 0 {
11775                let range_to_move = Point::new(
11776                    start_row.previous_row().0,
11777                    buffer.line_len(start_row.previous_row()),
11778                )
11779                    ..Point::new(
11780                        end_row.previous_row().0,
11781                        buffer.line_len(end_row.previous_row()),
11782                    );
11783                let insertion_point = display_map
11784                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11785                    .0;
11786
11787                // Don't move lines across excerpts
11788                if buffer
11789                    .excerpt_containing(insertion_point..range_to_move.end)
11790                    .is_some()
11791                {
11792                    let text = buffer
11793                        .text_for_range(range_to_move.clone())
11794                        .flat_map(|s| s.chars())
11795                        .skip(1)
11796                        .chain(['\n'])
11797                        .collect::<String>();
11798
11799                    edits.push((
11800                        buffer.anchor_after(range_to_move.start)
11801                            ..buffer.anchor_before(range_to_move.end),
11802                        String::new(),
11803                    ));
11804                    let insertion_anchor = buffer.anchor_after(insertion_point);
11805                    edits.push((insertion_anchor..insertion_anchor, text));
11806
11807                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11808
11809                    // Move selections up
11810                    new_selections.extend(contiguous_row_selections.drain(..).map(
11811                        |mut selection| {
11812                            selection.start.row -= row_delta;
11813                            selection.end.row -= row_delta;
11814                            selection
11815                        },
11816                    ));
11817
11818                    // Move folds up
11819                    unfold_ranges.push(range_to_move.clone());
11820                    for fold in display_map.folds_in_range(
11821                        buffer.anchor_before(range_to_move.start)
11822                            ..buffer.anchor_after(range_to_move.end),
11823                    ) {
11824                        let mut start = fold.range.start.to_point(&buffer);
11825                        let mut end = fold.range.end.to_point(&buffer);
11826                        start.row -= row_delta;
11827                        end.row -= row_delta;
11828                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11829                    }
11830                }
11831            }
11832
11833            // If we didn't move line(s), preserve the existing selections
11834            new_selections.append(&mut contiguous_row_selections);
11835        }
11836
11837        self.transact(window, cx, |this, window, cx| {
11838            this.unfold_ranges(&unfold_ranges, true, true, cx);
11839            this.buffer.update(cx, |buffer, cx| {
11840                for (range, text) in edits {
11841                    buffer.edit([(range, text)], None, cx);
11842                }
11843            });
11844            this.fold_creases(refold_creases, true, window, cx);
11845            this.change_selections(Default::default(), window, cx, |s| {
11846                s.select(new_selections);
11847            })
11848        });
11849    }
11850
11851    pub fn move_line_down(
11852        &mut self,
11853        _: &MoveLineDown,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856    ) {
11857        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11858        if self.mode.is_single_line() {
11859            cx.propagate();
11860            return;
11861        }
11862
11863        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11864        let buffer = self.buffer.read(cx).snapshot(cx);
11865
11866        let mut edits = Vec::new();
11867        let mut unfold_ranges = Vec::new();
11868        let mut refold_creases = Vec::new();
11869
11870        let selections = self.selections.all::<Point>(cx);
11871        let mut selections = selections.iter().peekable();
11872        let mut contiguous_row_selections = Vec::new();
11873        let mut new_selections = Vec::new();
11874
11875        while let Some(selection) = selections.next() {
11876            // Find all the selections that span a contiguous row range
11877            let (start_row, end_row) = consume_contiguous_rows(
11878                &mut contiguous_row_selections,
11879                selection,
11880                &display_map,
11881                &mut selections,
11882            );
11883
11884            // Move the text spanned by the row range to be after the last line of the row range
11885            if end_row.0 <= buffer.max_point().row {
11886                let range_to_move =
11887                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11888                let insertion_point = display_map
11889                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11890                    .0;
11891
11892                // Don't move lines across excerpt boundaries
11893                if buffer
11894                    .excerpt_containing(range_to_move.start..insertion_point)
11895                    .is_some()
11896                {
11897                    let mut text = String::from("\n");
11898                    text.extend(buffer.text_for_range(range_to_move.clone()));
11899                    text.pop(); // Drop trailing newline
11900                    edits.push((
11901                        buffer.anchor_after(range_to_move.start)
11902                            ..buffer.anchor_before(range_to_move.end),
11903                        String::new(),
11904                    ));
11905                    let insertion_anchor = buffer.anchor_after(insertion_point);
11906                    edits.push((insertion_anchor..insertion_anchor, text));
11907
11908                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11909
11910                    // Move selections down
11911                    new_selections.extend(contiguous_row_selections.drain(..).map(
11912                        |mut selection| {
11913                            selection.start.row += row_delta;
11914                            selection.end.row += row_delta;
11915                            selection
11916                        },
11917                    ));
11918
11919                    // Move folds down
11920                    unfold_ranges.push(range_to_move.clone());
11921                    for fold in display_map.folds_in_range(
11922                        buffer.anchor_before(range_to_move.start)
11923                            ..buffer.anchor_after(range_to_move.end),
11924                    ) {
11925                        let mut start = fold.range.start.to_point(&buffer);
11926                        let mut end = fold.range.end.to_point(&buffer);
11927                        start.row += row_delta;
11928                        end.row += row_delta;
11929                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11930                    }
11931                }
11932            }
11933
11934            // If we didn't move line(s), preserve the existing selections
11935            new_selections.append(&mut contiguous_row_selections);
11936        }
11937
11938        self.transact(window, cx, |this, window, cx| {
11939            this.unfold_ranges(&unfold_ranges, true, true, cx);
11940            this.buffer.update(cx, |buffer, cx| {
11941                for (range, text) in edits {
11942                    buffer.edit([(range, text)], None, cx);
11943                }
11944            });
11945            this.fold_creases(refold_creases, true, window, cx);
11946            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11947        });
11948    }
11949
11950    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11951        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11952        let text_layout_details = &self.text_layout_details(window);
11953        self.transact(window, cx, |this, window, cx| {
11954            let edits = this.change_selections(Default::default(), window, cx, |s| {
11955                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11956                s.move_with(|display_map, selection| {
11957                    if !selection.is_empty() {
11958                        return;
11959                    }
11960
11961                    let mut head = selection.head();
11962                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11963                    if head.column() == display_map.line_len(head.row()) {
11964                        transpose_offset = display_map
11965                            .buffer_snapshot()
11966                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11967                    }
11968
11969                    if transpose_offset == 0 {
11970                        return;
11971                    }
11972
11973                    *head.column_mut() += 1;
11974                    head = display_map.clip_point(head, Bias::Right);
11975                    let goal = SelectionGoal::HorizontalPosition(
11976                        display_map
11977                            .x_for_display_point(head, text_layout_details)
11978                            .into(),
11979                    );
11980                    selection.collapse_to(head, goal);
11981
11982                    let transpose_start = display_map
11983                        .buffer_snapshot()
11984                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11985                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11986                        let transpose_end = display_map
11987                            .buffer_snapshot()
11988                            .clip_offset(transpose_offset + 1, Bias::Right);
11989                        if let Some(ch) = display_map
11990                            .buffer_snapshot()
11991                            .chars_at(transpose_start)
11992                            .next()
11993                        {
11994                            edits.push((transpose_start..transpose_offset, String::new()));
11995                            edits.push((transpose_end..transpose_end, ch.to_string()));
11996                        }
11997                    }
11998                });
11999                edits
12000            });
12001            this.buffer
12002                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12003            let selections = this.selections.all::<usize>(cx);
12004            this.change_selections(Default::default(), window, cx, |s| {
12005                s.select(selections);
12006            });
12007        });
12008    }
12009
12010    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12012        if self.mode.is_single_line() {
12013            cx.propagate();
12014            return;
12015        }
12016
12017        self.rewrap_impl(RewrapOptions::default(), cx)
12018    }
12019
12020    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12021        let buffer = self.buffer.read(cx).snapshot(cx);
12022        let selections = self.selections.all::<Point>(cx);
12023
12024        #[derive(Clone, Debug, PartialEq)]
12025        enum CommentFormat {
12026            /// single line comment, with prefix for line
12027            Line(String),
12028            /// single line within a block comment, with prefix for line
12029            BlockLine(String),
12030            /// a single line of a block comment that includes the initial delimiter
12031            BlockCommentWithStart(BlockCommentConfig),
12032            /// a single line of a block comment that includes the ending delimiter
12033            BlockCommentWithEnd(BlockCommentConfig),
12034        }
12035
12036        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12037        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12038            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12039                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12040                .peekable();
12041
12042            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12043                row
12044            } else {
12045                return Vec::new();
12046            };
12047
12048            let language_settings = buffer.language_settings_at(selection.head(), cx);
12049            let language_scope = buffer.language_scope_at(selection.head());
12050
12051            let indent_and_prefix_for_row =
12052                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12053                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12054                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12055                        &language_scope
12056                    {
12057                        let indent_end = Point::new(row, indent.len);
12058                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12059                        let line_text_after_indent = buffer
12060                            .text_for_range(indent_end..line_end)
12061                            .collect::<String>();
12062
12063                        let is_within_comment_override = buffer
12064                            .language_scope_at(indent_end)
12065                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12066                        let comment_delimiters = if is_within_comment_override {
12067                            // we are within a comment syntax node, but we don't
12068                            // yet know what kind of comment: block, doc or line
12069                            match (
12070                                language_scope.documentation_comment(),
12071                                language_scope.block_comment(),
12072                            ) {
12073                                (Some(config), _) | (_, Some(config))
12074                                    if buffer.contains_str_at(indent_end, &config.start) =>
12075                                {
12076                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12077                                }
12078                                (Some(config), _) | (_, Some(config))
12079                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12080                                {
12081                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12082                                }
12083                                (Some(config), _) | (_, Some(config))
12084                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12085                                {
12086                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12087                                }
12088                                (_, _) => language_scope
12089                                    .line_comment_prefixes()
12090                                    .iter()
12091                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12092                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12093                            }
12094                        } else {
12095                            // we not in an overridden comment node, but we may
12096                            // be within a non-overridden line comment node
12097                            language_scope
12098                                .line_comment_prefixes()
12099                                .iter()
12100                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12101                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12102                        };
12103
12104                        let rewrap_prefix = language_scope
12105                            .rewrap_prefixes()
12106                            .iter()
12107                            .find_map(|prefix_regex| {
12108                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12109                                    if mat.start() == 0 {
12110                                        Some(mat.as_str().to_string())
12111                                    } else {
12112                                        None
12113                                    }
12114                                })
12115                            })
12116                            .flatten();
12117                        (comment_delimiters, rewrap_prefix)
12118                    } else {
12119                        (None, None)
12120                    };
12121                    (indent, comment_prefix, rewrap_prefix)
12122                };
12123
12124            let mut ranges = Vec::new();
12125            let from_empty_selection = selection.is_empty();
12126
12127            let mut current_range_start = first_row;
12128            let mut prev_row = first_row;
12129            let (
12130                mut current_range_indent,
12131                mut current_range_comment_delimiters,
12132                mut current_range_rewrap_prefix,
12133            ) = indent_and_prefix_for_row(first_row);
12134
12135            for row in non_blank_rows_iter.skip(1) {
12136                let has_paragraph_break = row > prev_row + 1;
12137
12138                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12139                    indent_and_prefix_for_row(row);
12140
12141                let has_indent_change = row_indent != current_range_indent;
12142                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12143
12144                let has_boundary_change = has_comment_change
12145                    || row_rewrap_prefix.is_some()
12146                    || (has_indent_change && current_range_comment_delimiters.is_some());
12147
12148                if has_paragraph_break || has_boundary_change {
12149                    ranges.push((
12150                        language_settings.clone(),
12151                        Point::new(current_range_start, 0)
12152                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12153                        current_range_indent,
12154                        current_range_comment_delimiters.clone(),
12155                        current_range_rewrap_prefix.clone(),
12156                        from_empty_selection,
12157                    ));
12158                    current_range_start = row;
12159                    current_range_indent = row_indent;
12160                    current_range_comment_delimiters = row_comment_delimiters;
12161                    current_range_rewrap_prefix = row_rewrap_prefix;
12162                }
12163                prev_row = row;
12164            }
12165
12166            ranges.push((
12167                language_settings.clone(),
12168                Point::new(current_range_start, 0)
12169                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12170                current_range_indent,
12171                current_range_comment_delimiters,
12172                current_range_rewrap_prefix,
12173                from_empty_selection,
12174            ));
12175
12176            ranges
12177        });
12178
12179        let mut edits = Vec::new();
12180        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12181
12182        for (
12183            language_settings,
12184            wrap_range,
12185            mut indent_size,
12186            comment_prefix,
12187            rewrap_prefix,
12188            from_empty_selection,
12189        ) in wrap_ranges
12190        {
12191            let mut start_row = wrap_range.start.row;
12192            let mut end_row = wrap_range.end.row;
12193
12194            // Skip selections that overlap with a range that has already been rewrapped.
12195            let selection_range = start_row..end_row;
12196            if rewrapped_row_ranges
12197                .iter()
12198                .any(|range| range.overlaps(&selection_range))
12199            {
12200                continue;
12201            }
12202
12203            let tab_size = language_settings.tab_size;
12204
12205            let (line_prefix, inside_comment) = match &comment_prefix {
12206                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12207                    (Some(prefix.as_str()), true)
12208                }
12209                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12210                    (Some(prefix.as_ref()), true)
12211                }
12212                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12213                    start: _,
12214                    end: _,
12215                    prefix,
12216                    tab_size,
12217                })) => {
12218                    indent_size.len += tab_size;
12219                    (Some(prefix.as_ref()), true)
12220                }
12221                None => (None, false),
12222            };
12223            let indent_prefix = indent_size.chars().collect::<String>();
12224            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12225
12226            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12227                RewrapBehavior::InComments => inside_comment,
12228                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12229                RewrapBehavior::Anywhere => true,
12230            };
12231
12232            let should_rewrap = options.override_language_settings
12233                || allow_rewrap_based_on_language
12234                || self.hard_wrap.is_some();
12235            if !should_rewrap {
12236                continue;
12237            }
12238
12239            if from_empty_selection {
12240                'expand_upwards: while start_row > 0 {
12241                    let prev_row = start_row - 1;
12242                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12243                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12244                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12245                    {
12246                        start_row = prev_row;
12247                    } else {
12248                        break 'expand_upwards;
12249                    }
12250                }
12251
12252                'expand_downwards: while end_row < buffer.max_point().row {
12253                    let next_row = end_row + 1;
12254                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12255                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12256                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12257                    {
12258                        end_row = next_row;
12259                    } else {
12260                        break 'expand_downwards;
12261                    }
12262                }
12263            }
12264
12265            let start = Point::new(start_row, 0);
12266            let start_offset = ToOffset::to_offset(&start, &buffer);
12267            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12268            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12269            let mut first_line_delimiter = None;
12270            let mut last_line_delimiter = None;
12271            let Some(lines_without_prefixes) = selection_text
12272                .lines()
12273                .enumerate()
12274                .map(|(ix, line)| {
12275                    let line_trimmed = line.trim_start();
12276                    if rewrap_prefix.is_some() && ix > 0 {
12277                        Ok(line_trimmed)
12278                    } else if let Some(
12279                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12280                            start,
12281                            prefix,
12282                            end,
12283                            tab_size,
12284                        })
12285                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12286                            start,
12287                            prefix,
12288                            end,
12289                            tab_size,
12290                        }),
12291                    ) = &comment_prefix
12292                    {
12293                        let line_trimmed = line_trimmed
12294                            .strip_prefix(start.as_ref())
12295                            .map(|s| {
12296                                let mut indent_size = indent_size;
12297                                indent_size.len -= tab_size;
12298                                let indent_prefix: String = indent_size.chars().collect();
12299                                first_line_delimiter = Some((indent_prefix, start));
12300                                s.trim_start()
12301                            })
12302                            .unwrap_or(line_trimmed);
12303                        let line_trimmed = line_trimmed
12304                            .strip_suffix(end.as_ref())
12305                            .map(|s| {
12306                                last_line_delimiter = Some(end);
12307                                s.trim_end()
12308                            })
12309                            .unwrap_or(line_trimmed);
12310                        let line_trimmed = line_trimmed
12311                            .strip_prefix(prefix.as_ref())
12312                            .unwrap_or(line_trimmed);
12313                        Ok(line_trimmed)
12314                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12315                        line_trimmed.strip_prefix(prefix).with_context(|| {
12316                            format!("line did not start with prefix {prefix:?}: {line:?}")
12317                        })
12318                    } else {
12319                        line_trimmed
12320                            .strip_prefix(&line_prefix.trim_start())
12321                            .with_context(|| {
12322                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12323                            })
12324                    }
12325                })
12326                .collect::<Result<Vec<_>, _>>()
12327                .log_err()
12328            else {
12329                continue;
12330            };
12331
12332            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12333                buffer
12334                    .language_settings_at(Point::new(start_row, 0), cx)
12335                    .preferred_line_length as usize
12336            });
12337
12338            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12339                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12340            } else {
12341                line_prefix.clone()
12342            };
12343
12344            let wrapped_text = {
12345                let mut wrapped_text = wrap_with_prefix(
12346                    line_prefix,
12347                    subsequent_lines_prefix,
12348                    lines_without_prefixes.join("\n"),
12349                    wrap_column,
12350                    tab_size,
12351                    options.preserve_existing_whitespace,
12352                );
12353
12354                if let Some((indent, delimiter)) = first_line_delimiter {
12355                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12356                }
12357                if let Some(last_line) = last_line_delimiter {
12358                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12359                }
12360
12361                wrapped_text
12362            };
12363
12364            // TODO: should always use char-based diff while still supporting cursor behavior that
12365            // matches vim.
12366            let mut diff_options = DiffOptions::default();
12367            if options.override_language_settings {
12368                diff_options.max_word_diff_len = 0;
12369                diff_options.max_word_diff_line_count = 0;
12370            } else {
12371                diff_options.max_word_diff_len = usize::MAX;
12372                diff_options.max_word_diff_line_count = usize::MAX;
12373            }
12374
12375            for (old_range, new_text) in
12376                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12377            {
12378                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12379                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12380                edits.push((edit_start..edit_end, new_text));
12381            }
12382
12383            rewrapped_row_ranges.push(start_row..=end_row);
12384        }
12385
12386        self.buffer
12387            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12388    }
12389
12390    pub fn cut_common(
12391        &mut self,
12392        cut_no_selection_line: bool,
12393        window: &mut Window,
12394        cx: &mut Context<Self>,
12395    ) -> ClipboardItem {
12396        let mut text = String::new();
12397        let buffer = self.buffer.read(cx).snapshot(cx);
12398        let mut selections = self.selections.all::<Point>(cx);
12399        let mut clipboard_selections = Vec::with_capacity(selections.len());
12400        {
12401            let max_point = buffer.max_point();
12402            let mut is_first = true;
12403            for selection in &mut selections {
12404                let is_entire_line =
12405                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12406                if is_entire_line {
12407                    selection.start = Point::new(selection.start.row, 0);
12408                    if !selection.is_empty() && selection.end.column == 0 {
12409                        selection.end = cmp::min(max_point, selection.end);
12410                    } else {
12411                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12412                    }
12413                    selection.goal = SelectionGoal::None;
12414                }
12415                if is_first {
12416                    is_first = false;
12417                } else {
12418                    text += "\n";
12419                }
12420                let mut len = 0;
12421                for chunk in buffer.text_for_range(selection.start..selection.end) {
12422                    text.push_str(chunk);
12423                    len += chunk.len();
12424                }
12425                clipboard_selections.push(ClipboardSelection {
12426                    len,
12427                    is_entire_line,
12428                    first_line_indent: buffer
12429                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12430                        .len,
12431                });
12432            }
12433        }
12434
12435        self.transact(window, cx, |this, window, cx| {
12436            this.change_selections(Default::default(), window, cx, |s| {
12437                s.select(selections);
12438            });
12439            this.insert("", window, cx);
12440        });
12441        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12442    }
12443
12444    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12445        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12446        let item = self.cut_common(true, window, cx);
12447        cx.write_to_clipboard(item);
12448    }
12449
12450    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12452        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12453            s.move_with(|snapshot, sel| {
12454                if sel.is_empty() {
12455                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12456                }
12457                if sel.is_empty() {
12458                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12459                }
12460            });
12461        });
12462        let item = self.cut_common(false, window, cx);
12463        cx.set_global(KillRing(item))
12464    }
12465
12466    pub fn kill_ring_yank(
12467        &mut self,
12468        _: &KillRingYank,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12473        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12474            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12475                (kill_ring.text().to_string(), kill_ring.metadata_json())
12476            } else {
12477                return;
12478            }
12479        } else {
12480            return;
12481        };
12482        self.do_paste(&text, metadata, false, window, cx);
12483    }
12484
12485    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12486        self.do_copy(true, cx);
12487    }
12488
12489    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12490        self.do_copy(false, cx);
12491    }
12492
12493    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12494        let selections = self.selections.all::<Point>(cx);
12495        let buffer = self.buffer.read(cx).read(cx);
12496        let mut text = String::new();
12497
12498        let mut clipboard_selections = Vec::with_capacity(selections.len());
12499        {
12500            let max_point = buffer.max_point();
12501            let mut is_first = true;
12502            for selection in &selections {
12503                let mut start = selection.start;
12504                let mut end = selection.end;
12505                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12506                if is_entire_line {
12507                    start = Point::new(start.row, 0);
12508                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12509                }
12510
12511                let mut trimmed_selections = Vec::new();
12512                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12513                    let row = MultiBufferRow(start.row);
12514                    let first_indent = buffer.indent_size_for_line(row);
12515                    if first_indent.len == 0 || start.column > first_indent.len {
12516                        trimmed_selections.push(start..end);
12517                    } else {
12518                        trimmed_selections.push(
12519                            Point::new(row.0, first_indent.len)
12520                                ..Point::new(row.0, buffer.line_len(row)),
12521                        );
12522                        for row in start.row + 1..=end.row {
12523                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12524                            if row == end.row {
12525                                line_len = end.column;
12526                            }
12527                            if line_len == 0 {
12528                                trimmed_selections
12529                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12530                                continue;
12531                            }
12532                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12533                            if row_indent_size.len >= first_indent.len {
12534                                trimmed_selections.push(
12535                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12536                                );
12537                            } else {
12538                                trimmed_selections.clear();
12539                                trimmed_selections.push(start..end);
12540                                break;
12541                            }
12542                        }
12543                    }
12544                } else {
12545                    trimmed_selections.push(start..end);
12546                }
12547
12548                for trimmed_range in trimmed_selections {
12549                    if is_first {
12550                        is_first = false;
12551                    } else {
12552                        text += "\n";
12553                    }
12554                    let mut len = 0;
12555                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12556                        text.push_str(chunk);
12557                        len += chunk.len();
12558                    }
12559                    clipboard_selections.push(ClipboardSelection {
12560                        len,
12561                        is_entire_line,
12562                        first_line_indent: buffer
12563                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12564                            .len,
12565                    });
12566                }
12567            }
12568        }
12569
12570        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12571            text,
12572            clipboard_selections,
12573        ));
12574    }
12575
12576    pub fn do_paste(
12577        &mut self,
12578        text: &String,
12579        clipboard_selections: Option<Vec<ClipboardSelection>>,
12580        handle_entire_lines: bool,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if self.read_only(cx) {
12585            return;
12586        }
12587
12588        let clipboard_text = Cow::Borrowed(text.as_str());
12589
12590        self.transact(window, cx, |this, window, cx| {
12591            let had_active_edit_prediction = this.has_active_edit_prediction();
12592            let old_selections = this.selections.all::<usize>(cx);
12593            let cursor_offset = this.selections.last::<usize>(cx).head();
12594
12595            if let Some(mut clipboard_selections) = clipboard_selections {
12596                let all_selections_were_entire_line =
12597                    clipboard_selections.iter().all(|s| s.is_entire_line);
12598                let first_selection_indent_column =
12599                    clipboard_selections.first().map(|s| s.first_line_indent);
12600                if clipboard_selections.len() != old_selections.len() {
12601                    clipboard_selections.drain(..);
12602                }
12603                let mut auto_indent_on_paste = true;
12604
12605                this.buffer.update(cx, |buffer, cx| {
12606                    let snapshot = buffer.read(cx);
12607                    auto_indent_on_paste = snapshot
12608                        .language_settings_at(cursor_offset, cx)
12609                        .auto_indent_on_paste;
12610
12611                    let mut start_offset = 0;
12612                    let mut edits = Vec::new();
12613                    let mut original_indent_columns = Vec::new();
12614                    for (ix, selection) in old_selections.iter().enumerate() {
12615                        let to_insert;
12616                        let entire_line;
12617                        let original_indent_column;
12618                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12619                            let end_offset = start_offset + clipboard_selection.len;
12620                            to_insert = &clipboard_text[start_offset..end_offset];
12621                            entire_line = clipboard_selection.is_entire_line;
12622                            start_offset = end_offset + 1;
12623                            original_indent_column = Some(clipboard_selection.first_line_indent);
12624                        } else {
12625                            to_insert = &*clipboard_text;
12626                            entire_line = all_selections_were_entire_line;
12627                            original_indent_column = first_selection_indent_column
12628                        }
12629
12630                        let (range, to_insert) =
12631                            if selection.is_empty() && handle_entire_lines && entire_line {
12632                                // If the corresponding selection was empty when this slice of the
12633                                // clipboard text was written, then the entire line containing the
12634                                // selection was copied. If this selection is also currently empty,
12635                                // then paste the line before the current line of the buffer.
12636                                let column = selection.start.to_point(&snapshot).column as usize;
12637                                let line_start = selection.start - column;
12638                                (line_start..line_start, Cow::Borrowed(to_insert))
12639                            } else {
12640                                let language = snapshot.language_at(selection.head());
12641                                let range = selection.range();
12642                                if let Some(language) = language
12643                                    && language.name() == "Markdown".into()
12644                                {
12645                                    edit_for_markdown_paste(
12646                                        &snapshot,
12647                                        range,
12648                                        to_insert,
12649                                        url::Url::parse(to_insert).ok(),
12650                                    )
12651                                } else {
12652                                    (range, Cow::Borrowed(to_insert))
12653                                }
12654                            };
12655
12656                        edits.push((range, to_insert));
12657                        original_indent_columns.push(original_indent_column);
12658                    }
12659                    drop(snapshot);
12660
12661                    buffer.edit(
12662                        edits,
12663                        if auto_indent_on_paste {
12664                            Some(AutoindentMode::Block {
12665                                original_indent_columns,
12666                            })
12667                        } else {
12668                            None
12669                        },
12670                        cx,
12671                    );
12672                });
12673
12674                let selections = this.selections.all::<usize>(cx);
12675                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12676            } else {
12677                let url = url::Url::parse(&clipboard_text).ok();
12678
12679                let auto_indent_mode = if !clipboard_text.is_empty() {
12680                    Some(AutoindentMode::Block {
12681                        original_indent_columns: Vec::new(),
12682                    })
12683                } else {
12684                    None
12685                };
12686
12687                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12688                    let snapshot = buffer.snapshot(cx);
12689
12690                    let anchors = old_selections
12691                        .iter()
12692                        .map(|s| {
12693                            let anchor = snapshot.anchor_after(s.head());
12694                            s.map(|_| anchor)
12695                        })
12696                        .collect::<Vec<_>>();
12697
12698                    let mut edits = Vec::new();
12699
12700                    for selection in old_selections.iter() {
12701                        let language = snapshot.language_at(selection.head());
12702                        let range = selection.range();
12703
12704                        let (edit_range, edit_text) = if let Some(language) = language
12705                            && language.name() == "Markdown".into()
12706                        {
12707                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12708                        } else {
12709                            (range, clipboard_text.clone())
12710                        };
12711
12712                        edits.push((edit_range, edit_text));
12713                    }
12714
12715                    drop(snapshot);
12716                    buffer.edit(edits, auto_indent_mode, cx);
12717
12718                    anchors
12719                });
12720
12721                this.change_selections(Default::default(), window, cx, |s| {
12722                    s.select_anchors(selection_anchors);
12723                });
12724            }
12725
12726            let trigger_in_words =
12727                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12728
12729            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12730        });
12731    }
12732
12733    pub fn diff_clipboard_with_selection(
12734        &mut self,
12735        _: &DiffClipboardWithSelection,
12736        window: &mut Window,
12737        cx: &mut Context<Self>,
12738    ) {
12739        let selections = self.selections.all::<usize>(cx);
12740
12741        if selections.is_empty() {
12742            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12743            return;
12744        };
12745
12746        let clipboard_text = match cx.read_from_clipboard() {
12747            Some(item) => match item.entries().first() {
12748                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12749                _ => None,
12750            },
12751            None => None,
12752        };
12753
12754        let Some(clipboard_text) = clipboard_text else {
12755            log::warn!("Clipboard doesn't contain text.");
12756            return;
12757        };
12758
12759        window.dispatch_action(
12760            Box::new(DiffClipboardWithSelectionData {
12761                clipboard_text,
12762                editor: cx.entity(),
12763            }),
12764            cx,
12765        );
12766    }
12767
12768    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12770        if let Some(item) = cx.read_from_clipboard() {
12771            let entries = item.entries();
12772
12773            match entries.first() {
12774                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12775                // of all the pasted entries.
12776                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12777                    .do_paste(
12778                        clipboard_string.text(),
12779                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12780                        true,
12781                        window,
12782                        cx,
12783                    ),
12784                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12785            }
12786        }
12787    }
12788
12789    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12790        if self.read_only(cx) {
12791            return;
12792        }
12793
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12795
12796        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12797            if let Some((selections, _)) =
12798                self.selection_history.transaction(transaction_id).cloned()
12799            {
12800                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12801                    s.select_anchors(selections.to_vec());
12802                });
12803            } else {
12804                log::error!(
12805                    "No entry in selection_history found for undo. \
12806                     This may correspond to a bug where undo does not update the selection. \
12807                     If this is occurring, please add details to \
12808                     https://github.com/zed-industries/zed/issues/22692"
12809                );
12810            }
12811            self.request_autoscroll(Autoscroll::fit(), cx);
12812            self.unmark_text(window, cx);
12813            self.refresh_edit_prediction(true, false, window, cx);
12814            cx.emit(EditorEvent::Edited { transaction_id });
12815            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12816        }
12817    }
12818
12819    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12820        if self.read_only(cx) {
12821            return;
12822        }
12823
12824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12825
12826        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12827            if let Some((_, Some(selections))) =
12828                self.selection_history.transaction(transaction_id).cloned()
12829            {
12830                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12831                    s.select_anchors(selections.to_vec());
12832                });
12833            } else {
12834                log::error!(
12835                    "No entry in selection_history found for redo. \
12836                     This may correspond to a bug where undo does not update the selection. \
12837                     If this is occurring, please add details to \
12838                     https://github.com/zed-industries/zed/issues/22692"
12839                );
12840            }
12841            self.request_autoscroll(Autoscroll::fit(), cx);
12842            self.unmark_text(window, cx);
12843            self.refresh_edit_prediction(true, false, window, cx);
12844            cx.emit(EditorEvent::Edited { transaction_id });
12845        }
12846    }
12847
12848    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12849        self.buffer
12850            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12851    }
12852
12853    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12854        self.buffer
12855            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12856    }
12857
12858    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12860        self.change_selections(Default::default(), window, cx, |s| {
12861            s.move_with(|map, selection| {
12862                let cursor = if selection.is_empty() {
12863                    movement::left(map, selection.start)
12864                } else {
12865                    selection.start
12866                };
12867                selection.collapse_to(cursor, SelectionGoal::None);
12868            });
12869        })
12870    }
12871
12872    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12873        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12874        self.change_selections(Default::default(), window, cx, |s| {
12875            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12876        })
12877    }
12878
12879    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12881        self.change_selections(Default::default(), window, cx, |s| {
12882            s.move_with(|map, selection| {
12883                let cursor = if selection.is_empty() {
12884                    movement::right(map, selection.end)
12885                } else {
12886                    selection.end
12887                };
12888                selection.collapse_to(cursor, SelectionGoal::None)
12889            });
12890        })
12891    }
12892
12893    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895        self.change_selections(Default::default(), window, cx, |s| {
12896            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12897        });
12898    }
12899
12900    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12901        if self.take_rename(true, window, cx).is_some() {
12902            return;
12903        }
12904
12905        if self.mode.is_single_line() {
12906            cx.propagate();
12907            return;
12908        }
12909
12910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12911
12912        let text_layout_details = &self.text_layout_details(window);
12913        let selection_count = self.selections.count();
12914        let first_selection = self.selections.first_anchor();
12915
12916        self.change_selections(Default::default(), window, cx, |s| {
12917            s.move_with(|map, selection| {
12918                if !selection.is_empty() {
12919                    selection.goal = SelectionGoal::None;
12920                }
12921                let (cursor, goal) = movement::up(
12922                    map,
12923                    selection.start,
12924                    selection.goal,
12925                    false,
12926                    text_layout_details,
12927                );
12928                selection.collapse_to(cursor, goal);
12929            });
12930        });
12931
12932        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12933        {
12934            cx.propagate();
12935        }
12936    }
12937
12938    pub fn move_up_by_lines(
12939        &mut self,
12940        action: &MoveUpByLines,
12941        window: &mut Window,
12942        cx: &mut Context<Self>,
12943    ) {
12944        if self.take_rename(true, window, cx).is_some() {
12945            return;
12946        }
12947
12948        if self.mode.is_single_line() {
12949            cx.propagate();
12950            return;
12951        }
12952
12953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12954
12955        let text_layout_details = &self.text_layout_details(window);
12956
12957        self.change_selections(Default::default(), window, cx, |s| {
12958            s.move_with(|map, selection| {
12959                if !selection.is_empty() {
12960                    selection.goal = SelectionGoal::None;
12961                }
12962                let (cursor, goal) = movement::up_by_rows(
12963                    map,
12964                    selection.start,
12965                    action.lines,
12966                    selection.goal,
12967                    false,
12968                    text_layout_details,
12969                );
12970                selection.collapse_to(cursor, goal);
12971            });
12972        })
12973    }
12974
12975    pub fn move_down_by_lines(
12976        &mut self,
12977        action: &MoveDownByLines,
12978        window: &mut Window,
12979        cx: &mut Context<Self>,
12980    ) {
12981        if self.take_rename(true, window, cx).is_some() {
12982            return;
12983        }
12984
12985        if self.mode.is_single_line() {
12986            cx.propagate();
12987            return;
12988        }
12989
12990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12991
12992        let text_layout_details = &self.text_layout_details(window);
12993
12994        self.change_selections(Default::default(), window, cx, |s| {
12995            s.move_with(|map, selection| {
12996                if !selection.is_empty() {
12997                    selection.goal = SelectionGoal::None;
12998                }
12999                let (cursor, goal) = movement::down_by_rows(
13000                    map,
13001                    selection.start,
13002                    action.lines,
13003                    selection.goal,
13004                    false,
13005                    text_layout_details,
13006                );
13007                selection.collapse_to(cursor, goal);
13008            });
13009        })
13010    }
13011
13012    pub fn select_down_by_lines(
13013        &mut self,
13014        action: &SelectDownByLines,
13015        window: &mut Window,
13016        cx: &mut Context<Self>,
13017    ) {
13018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13019        let text_layout_details = &self.text_layout_details(window);
13020        self.change_selections(Default::default(), window, cx, |s| {
13021            s.move_heads_with(|map, head, goal| {
13022                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13023            })
13024        })
13025    }
13026
13027    pub fn select_up_by_lines(
13028        &mut self,
13029        action: &SelectUpByLines,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13034        let text_layout_details = &self.text_layout_details(window);
13035        self.change_selections(Default::default(), window, cx, |s| {
13036            s.move_heads_with(|map, head, goal| {
13037                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13038            })
13039        })
13040    }
13041
13042    pub fn select_page_up(
13043        &mut self,
13044        _: &SelectPageUp,
13045        window: &mut Window,
13046        cx: &mut Context<Self>,
13047    ) {
13048        let Some(row_count) = self.visible_row_count() else {
13049            return;
13050        };
13051
13052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13053
13054        let text_layout_details = &self.text_layout_details(window);
13055
13056        self.change_selections(Default::default(), window, cx, |s| {
13057            s.move_heads_with(|map, head, goal| {
13058                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13059            })
13060        })
13061    }
13062
13063    pub fn move_page_up(
13064        &mut self,
13065        action: &MovePageUp,
13066        window: &mut Window,
13067        cx: &mut Context<Self>,
13068    ) {
13069        if self.take_rename(true, window, cx).is_some() {
13070            return;
13071        }
13072
13073        if self
13074            .context_menu
13075            .borrow_mut()
13076            .as_mut()
13077            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13078            .unwrap_or(false)
13079        {
13080            return;
13081        }
13082
13083        if matches!(self.mode, EditorMode::SingleLine) {
13084            cx.propagate();
13085            return;
13086        }
13087
13088        let Some(row_count) = self.visible_row_count() else {
13089            return;
13090        };
13091
13092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13093
13094        let effects = if action.center_cursor {
13095            SelectionEffects::scroll(Autoscroll::center())
13096        } else {
13097            SelectionEffects::default()
13098        };
13099
13100        let text_layout_details = &self.text_layout_details(window);
13101
13102        self.change_selections(effects, window, cx, |s| {
13103            s.move_with(|map, selection| {
13104                if !selection.is_empty() {
13105                    selection.goal = SelectionGoal::None;
13106                }
13107                let (cursor, goal) = movement::up_by_rows(
13108                    map,
13109                    selection.end,
13110                    row_count,
13111                    selection.goal,
13112                    false,
13113                    text_layout_details,
13114                );
13115                selection.collapse_to(cursor, goal);
13116            });
13117        });
13118    }
13119
13120    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122        let text_layout_details = &self.text_layout_details(window);
13123        self.change_selections(Default::default(), window, cx, |s| {
13124            s.move_heads_with(|map, head, goal| {
13125                movement::up(map, head, goal, false, text_layout_details)
13126            })
13127        })
13128    }
13129
13130    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13131        self.take_rename(true, window, cx);
13132
13133        if self.mode.is_single_line() {
13134            cx.propagate();
13135            return;
13136        }
13137
13138        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13139
13140        let text_layout_details = &self.text_layout_details(window);
13141        let selection_count = self.selections.count();
13142        let first_selection = self.selections.first_anchor();
13143
13144        self.change_selections(Default::default(), window, cx, |s| {
13145            s.move_with(|map, selection| {
13146                if !selection.is_empty() {
13147                    selection.goal = SelectionGoal::None;
13148                }
13149                let (cursor, goal) = movement::down(
13150                    map,
13151                    selection.end,
13152                    selection.goal,
13153                    false,
13154                    text_layout_details,
13155                );
13156                selection.collapse_to(cursor, goal);
13157            });
13158        });
13159
13160        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13161        {
13162            cx.propagate();
13163        }
13164    }
13165
13166    pub fn select_page_down(
13167        &mut self,
13168        _: &SelectPageDown,
13169        window: &mut Window,
13170        cx: &mut Context<Self>,
13171    ) {
13172        let Some(row_count) = self.visible_row_count() else {
13173            return;
13174        };
13175
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13177
13178        let text_layout_details = &self.text_layout_details(window);
13179
13180        self.change_selections(Default::default(), window, cx, |s| {
13181            s.move_heads_with(|map, head, goal| {
13182                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13183            })
13184        })
13185    }
13186
13187    pub fn move_page_down(
13188        &mut self,
13189        action: &MovePageDown,
13190        window: &mut Window,
13191        cx: &mut Context<Self>,
13192    ) {
13193        if self.take_rename(true, window, cx).is_some() {
13194            return;
13195        }
13196
13197        if self
13198            .context_menu
13199            .borrow_mut()
13200            .as_mut()
13201            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13202            .unwrap_or(false)
13203        {
13204            return;
13205        }
13206
13207        if matches!(self.mode, EditorMode::SingleLine) {
13208            cx.propagate();
13209            return;
13210        }
13211
13212        let Some(row_count) = self.visible_row_count() else {
13213            return;
13214        };
13215
13216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13217
13218        let effects = if action.center_cursor {
13219            SelectionEffects::scroll(Autoscroll::center())
13220        } else {
13221            SelectionEffects::default()
13222        };
13223
13224        let text_layout_details = &self.text_layout_details(window);
13225        self.change_selections(effects, window, cx, |s| {
13226            s.move_with(|map, selection| {
13227                if !selection.is_empty() {
13228                    selection.goal = SelectionGoal::None;
13229                }
13230                let (cursor, goal) = movement::down_by_rows(
13231                    map,
13232                    selection.end,
13233                    row_count,
13234                    selection.goal,
13235                    false,
13236                    text_layout_details,
13237                );
13238                selection.collapse_to(cursor, goal);
13239            });
13240        });
13241    }
13242
13243    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        let text_layout_details = &self.text_layout_details(window);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_heads_with(|map, head, goal| {
13248                movement::down(map, head, goal, false, text_layout_details)
13249            })
13250        });
13251    }
13252
13253    pub fn context_menu_first(
13254        &mut self,
13255        _: &ContextMenuFirst,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13260            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13261        }
13262    }
13263
13264    pub fn context_menu_prev(
13265        &mut self,
13266        _: &ContextMenuPrevious,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13271            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13272        }
13273    }
13274
13275    pub fn context_menu_next(
13276        &mut self,
13277        _: &ContextMenuNext,
13278        window: &mut Window,
13279        cx: &mut Context<Self>,
13280    ) {
13281        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13282            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13283        }
13284    }
13285
13286    pub fn context_menu_last(
13287        &mut self,
13288        _: &ContextMenuLast,
13289        window: &mut Window,
13290        cx: &mut Context<Self>,
13291    ) {
13292        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13293            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13294        }
13295    }
13296
13297    pub fn signature_help_prev(
13298        &mut self,
13299        _: &SignatureHelpPrevious,
13300        _: &mut Window,
13301        cx: &mut Context<Self>,
13302    ) {
13303        if let Some(popover) = self.signature_help_state.popover_mut() {
13304            if popover.current_signature == 0 {
13305                popover.current_signature = popover.signatures.len() - 1;
13306            } else {
13307                popover.current_signature -= 1;
13308            }
13309            cx.notify();
13310        }
13311    }
13312
13313    pub fn signature_help_next(
13314        &mut self,
13315        _: &SignatureHelpNext,
13316        _: &mut Window,
13317        cx: &mut Context<Self>,
13318    ) {
13319        if let Some(popover) = self.signature_help_state.popover_mut() {
13320            if popover.current_signature + 1 == popover.signatures.len() {
13321                popover.current_signature = 0;
13322            } else {
13323                popover.current_signature += 1;
13324            }
13325            cx.notify();
13326        }
13327    }
13328
13329    pub fn move_to_previous_word_start(
13330        &mut self,
13331        _: &MoveToPreviousWordStart,
13332        window: &mut Window,
13333        cx: &mut Context<Self>,
13334    ) {
13335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_cursors_with(|map, head, _| {
13338                (
13339                    movement::previous_word_start(map, head),
13340                    SelectionGoal::None,
13341                )
13342            });
13343        })
13344    }
13345
13346    pub fn move_to_previous_subword_start(
13347        &mut self,
13348        _: &MoveToPreviousSubwordStart,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.move_cursors_with(|map, head, _| {
13355                (
13356                    movement::previous_subword_start(map, head),
13357                    SelectionGoal::None,
13358                )
13359            });
13360        })
13361    }
13362
13363    pub fn select_to_previous_word_start(
13364        &mut self,
13365        _: &SelectToPreviousWordStart,
13366        window: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) {
13369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13370        self.change_selections(Default::default(), window, cx, |s| {
13371            s.move_heads_with(|map, head, _| {
13372                (
13373                    movement::previous_word_start(map, head),
13374                    SelectionGoal::None,
13375                )
13376            });
13377        })
13378    }
13379
13380    pub fn select_to_previous_subword_start(
13381        &mut self,
13382        _: &SelectToPreviousSubwordStart,
13383        window: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) {
13386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13387        self.change_selections(Default::default(), window, cx, |s| {
13388            s.move_heads_with(|map, head, _| {
13389                (
13390                    movement::previous_subword_start(map, head),
13391                    SelectionGoal::None,
13392                )
13393            });
13394        })
13395    }
13396
13397    pub fn delete_to_previous_word_start(
13398        &mut self,
13399        action: &DeleteToPreviousWordStart,
13400        window: &mut Window,
13401        cx: &mut Context<Self>,
13402    ) {
13403        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13404        self.transact(window, cx, |this, window, cx| {
13405            this.select_autoclose_pair(window, cx);
13406            this.change_selections(Default::default(), window, cx, |s| {
13407                s.move_with(|map, selection| {
13408                    if selection.is_empty() {
13409                        let mut cursor = if action.ignore_newlines {
13410                            movement::previous_word_start(map, selection.head())
13411                        } else {
13412                            movement::previous_word_start_or_newline(map, selection.head())
13413                        };
13414                        cursor = movement::adjust_greedy_deletion(
13415                            map,
13416                            selection.head(),
13417                            cursor,
13418                            action.ignore_brackets,
13419                        );
13420                        selection.set_head(cursor, SelectionGoal::None);
13421                    }
13422                });
13423            });
13424            this.insert("", window, cx);
13425        });
13426    }
13427
13428    pub fn delete_to_previous_subword_start(
13429        &mut self,
13430        _: &DeleteToPreviousSubwordStart,
13431        window: &mut Window,
13432        cx: &mut Context<Self>,
13433    ) {
13434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13435        self.transact(window, cx, |this, window, cx| {
13436            this.select_autoclose_pair(window, cx);
13437            this.change_selections(Default::default(), window, cx, |s| {
13438                s.move_with(|map, selection| {
13439                    if selection.is_empty() {
13440                        let mut cursor = movement::previous_subword_start(map, selection.head());
13441                        cursor =
13442                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13443                        selection.set_head(cursor, SelectionGoal::None);
13444                    }
13445                });
13446            });
13447            this.insert("", window, cx);
13448        });
13449    }
13450
13451    pub fn move_to_next_word_end(
13452        &mut self,
13453        _: &MoveToNextWordEnd,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_cursors_with(|map, head, _| {
13460                (movement::next_word_end(map, head), SelectionGoal::None)
13461            });
13462        })
13463    }
13464
13465    pub fn move_to_next_subword_end(
13466        &mut self,
13467        _: &MoveToNextSubwordEnd,
13468        window: &mut Window,
13469        cx: &mut Context<Self>,
13470    ) {
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13472        self.change_selections(Default::default(), window, cx, |s| {
13473            s.move_cursors_with(|map, head, _| {
13474                (movement::next_subword_end(map, head), SelectionGoal::None)
13475            });
13476        })
13477    }
13478
13479    pub fn select_to_next_word_end(
13480        &mut self,
13481        _: &SelectToNextWordEnd,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13486        self.change_selections(Default::default(), window, cx, |s| {
13487            s.move_heads_with(|map, head, _| {
13488                (movement::next_word_end(map, head), SelectionGoal::None)
13489            });
13490        })
13491    }
13492
13493    pub fn select_to_next_subword_end(
13494        &mut self,
13495        _: &SelectToNextSubwordEnd,
13496        window: &mut Window,
13497        cx: &mut Context<Self>,
13498    ) {
13499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13500        self.change_selections(Default::default(), window, cx, |s| {
13501            s.move_heads_with(|map, head, _| {
13502                (movement::next_subword_end(map, head), SelectionGoal::None)
13503            });
13504        })
13505    }
13506
13507    pub fn delete_to_next_word_end(
13508        &mut self,
13509        action: &DeleteToNextWordEnd,
13510        window: &mut Window,
13511        cx: &mut Context<Self>,
13512    ) {
13513        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13514        self.transact(window, cx, |this, window, cx| {
13515            this.change_selections(Default::default(), window, cx, |s| {
13516                s.move_with(|map, selection| {
13517                    if selection.is_empty() {
13518                        let mut cursor = if action.ignore_newlines {
13519                            movement::next_word_end(map, selection.head())
13520                        } else {
13521                            movement::next_word_end_or_newline(map, selection.head())
13522                        };
13523                        cursor = movement::adjust_greedy_deletion(
13524                            map,
13525                            selection.head(),
13526                            cursor,
13527                            action.ignore_brackets,
13528                        );
13529                        selection.set_head(cursor, SelectionGoal::None);
13530                    }
13531                });
13532            });
13533            this.insert("", window, cx);
13534        });
13535    }
13536
13537    pub fn delete_to_next_subword_end(
13538        &mut self,
13539        _: &DeleteToNextSubwordEnd,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13544        self.transact(window, cx, |this, window, cx| {
13545            this.change_selections(Default::default(), window, cx, |s| {
13546                s.move_with(|map, selection| {
13547                    if selection.is_empty() {
13548                        let mut cursor = movement::next_subword_end(map, selection.head());
13549                        cursor =
13550                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13551                        selection.set_head(cursor, SelectionGoal::None);
13552                    }
13553                });
13554            });
13555            this.insert("", window, cx);
13556        });
13557    }
13558
13559    pub fn move_to_beginning_of_line(
13560        &mut self,
13561        action: &MoveToBeginningOfLine,
13562        window: &mut Window,
13563        cx: &mut Context<Self>,
13564    ) {
13565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13566        self.change_selections(Default::default(), window, cx, |s| {
13567            s.move_cursors_with(|map, head, _| {
13568                (
13569                    movement::indented_line_beginning(
13570                        map,
13571                        head,
13572                        action.stop_at_soft_wraps,
13573                        action.stop_at_indent,
13574                    ),
13575                    SelectionGoal::None,
13576                )
13577            });
13578        })
13579    }
13580
13581    pub fn select_to_beginning_of_line(
13582        &mut self,
13583        action: &SelectToBeginningOfLine,
13584        window: &mut Window,
13585        cx: &mut Context<Self>,
13586    ) {
13587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13588        self.change_selections(Default::default(), window, cx, |s| {
13589            s.move_heads_with(|map, head, _| {
13590                (
13591                    movement::indented_line_beginning(
13592                        map,
13593                        head,
13594                        action.stop_at_soft_wraps,
13595                        action.stop_at_indent,
13596                    ),
13597                    SelectionGoal::None,
13598                )
13599            });
13600        });
13601    }
13602
13603    pub fn delete_to_beginning_of_line(
13604        &mut self,
13605        action: &DeleteToBeginningOfLine,
13606        window: &mut Window,
13607        cx: &mut Context<Self>,
13608    ) {
13609        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13610        self.transact(window, cx, |this, window, cx| {
13611            this.change_selections(Default::default(), window, cx, |s| {
13612                s.move_with(|_, selection| {
13613                    selection.reversed = true;
13614                });
13615            });
13616
13617            this.select_to_beginning_of_line(
13618                &SelectToBeginningOfLine {
13619                    stop_at_soft_wraps: false,
13620                    stop_at_indent: action.stop_at_indent,
13621                },
13622                window,
13623                cx,
13624            );
13625            this.backspace(&Backspace, window, cx);
13626        });
13627    }
13628
13629    pub fn move_to_end_of_line(
13630        &mut self,
13631        action: &MoveToEndOfLine,
13632        window: &mut Window,
13633        cx: &mut Context<Self>,
13634    ) {
13635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13636        self.change_selections(Default::default(), window, cx, |s| {
13637            s.move_cursors_with(|map, head, _| {
13638                (
13639                    movement::line_end(map, head, action.stop_at_soft_wraps),
13640                    SelectionGoal::None,
13641                )
13642            });
13643        })
13644    }
13645
13646    pub fn select_to_end_of_line(
13647        &mut self,
13648        action: &SelectToEndOfLine,
13649        window: &mut Window,
13650        cx: &mut Context<Self>,
13651    ) {
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, _| {
13655                (
13656                    movement::line_end(map, head, action.stop_at_soft_wraps),
13657                    SelectionGoal::None,
13658                )
13659            });
13660        })
13661    }
13662
13663    pub fn delete_to_end_of_line(
13664        &mut self,
13665        _: &DeleteToEndOfLine,
13666        window: &mut Window,
13667        cx: &mut Context<Self>,
13668    ) {
13669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13670        self.transact(window, cx, |this, window, cx| {
13671            this.select_to_end_of_line(
13672                &SelectToEndOfLine {
13673                    stop_at_soft_wraps: false,
13674                },
13675                window,
13676                cx,
13677            );
13678            this.delete(&Delete, window, cx);
13679        });
13680    }
13681
13682    pub fn cut_to_end_of_line(
13683        &mut self,
13684        action: &CutToEndOfLine,
13685        window: &mut Window,
13686        cx: &mut Context<Self>,
13687    ) {
13688        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13689        self.transact(window, cx, |this, window, cx| {
13690            this.select_to_end_of_line(
13691                &SelectToEndOfLine {
13692                    stop_at_soft_wraps: false,
13693                },
13694                window,
13695                cx,
13696            );
13697            if !action.stop_at_newlines {
13698                this.change_selections(Default::default(), window, cx, |s| {
13699                    s.move_with(|_, sel| {
13700                        if sel.is_empty() {
13701                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13702                        }
13703                    });
13704                });
13705            }
13706            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13707            let item = this.cut_common(false, window, cx);
13708            cx.write_to_clipboard(item);
13709        });
13710    }
13711
13712    pub fn move_to_start_of_paragraph(
13713        &mut self,
13714        _: &MoveToStartOfParagraph,
13715        window: &mut Window,
13716        cx: &mut Context<Self>,
13717    ) {
13718        if matches!(self.mode, EditorMode::SingleLine) {
13719            cx.propagate();
13720            return;
13721        }
13722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13723        self.change_selections(Default::default(), window, cx, |s| {
13724            s.move_with(|map, selection| {
13725                selection.collapse_to(
13726                    movement::start_of_paragraph(map, selection.head(), 1),
13727                    SelectionGoal::None,
13728                )
13729            });
13730        })
13731    }
13732
13733    pub fn move_to_end_of_paragraph(
13734        &mut self,
13735        _: &MoveToEndOfParagraph,
13736        window: &mut Window,
13737        cx: &mut Context<Self>,
13738    ) {
13739        if matches!(self.mode, EditorMode::SingleLine) {
13740            cx.propagate();
13741            return;
13742        }
13743        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13744        self.change_selections(Default::default(), window, cx, |s| {
13745            s.move_with(|map, selection| {
13746                selection.collapse_to(
13747                    movement::end_of_paragraph(map, selection.head(), 1),
13748                    SelectionGoal::None,
13749                )
13750            });
13751        })
13752    }
13753
13754    pub fn select_to_start_of_paragraph(
13755        &mut self,
13756        _: &SelectToStartOfParagraph,
13757        window: &mut Window,
13758        cx: &mut Context<Self>,
13759    ) {
13760        if matches!(self.mode, EditorMode::SingleLine) {
13761            cx.propagate();
13762            return;
13763        }
13764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13765        self.change_selections(Default::default(), window, cx, |s| {
13766            s.move_heads_with(|map, head, _| {
13767                (
13768                    movement::start_of_paragraph(map, head, 1),
13769                    SelectionGoal::None,
13770                )
13771            });
13772        })
13773    }
13774
13775    pub fn select_to_end_of_paragraph(
13776        &mut self,
13777        _: &SelectToEndOfParagraph,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) {
13781        if matches!(self.mode, EditorMode::SingleLine) {
13782            cx.propagate();
13783            return;
13784        }
13785        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13786        self.change_selections(Default::default(), window, cx, |s| {
13787            s.move_heads_with(|map, head, _| {
13788                (
13789                    movement::end_of_paragraph(map, head, 1),
13790                    SelectionGoal::None,
13791                )
13792            });
13793        })
13794    }
13795
13796    pub fn move_to_start_of_excerpt(
13797        &mut self,
13798        _: &MoveToStartOfExcerpt,
13799        window: &mut Window,
13800        cx: &mut Context<Self>,
13801    ) {
13802        if matches!(self.mode, EditorMode::SingleLine) {
13803            cx.propagate();
13804            return;
13805        }
13806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13807        self.change_selections(Default::default(), window, cx, |s| {
13808            s.move_with(|map, selection| {
13809                selection.collapse_to(
13810                    movement::start_of_excerpt(
13811                        map,
13812                        selection.head(),
13813                        workspace::searchable::Direction::Prev,
13814                    ),
13815                    SelectionGoal::None,
13816                )
13817            });
13818        })
13819    }
13820
13821    pub fn move_to_start_of_next_excerpt(
13822        &mut self,
13823        _: &MoveToStartOfNextExcerpt,
13824        window: &mut Window,
13825        cx: &mut Context<Self>,
13826    ) {
13827        if matches!(self.mode, EditorMode::SingleLine) {
13828            cx.propagate();
13829            return;
13830        }
13831
13832        self.change_selections(Default::default(), window, cx, |s| {
13833            s.move_with(|map, selection| {
13834                selection.collapse_to(
13835                    movement::start_of_excerpt(
13836                        map,
13837                        selection.head(),
13838                        workspace::searchable::Direction::Next,
13839                    ),
13840                    SelectionGoal::None,
13841                )
13842            });
13843        })
13844    }
13845
13846    pub fn move_to_end_of_excerpt(
13847        &mut self,
13848        _: &MoveToEndOfExcerpt,
13849        window: &mut Window,
13850        cx: &mut Context<Self>,
13851    ) {
13852        if matches!(self.mode, EditorMode::SingleLine) {
13853            cx.propagate();
13854            return;
13855        }
13856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13857        self.change_selections(Default::default(), window, cx, |s| {
13858            s.move_with(|map, selection| {
13859                selection.collapse_to(
13860                    movement::end_of_excerpt(
13861                        map,
13862                        selection.head(),
13863                        workspace::searchable::Direction::Next,
13864                    ),
13865                    SelectionGoal::None,
13866                )
13867            });
13868        })
13869    }
13870
13871    pub fn move_to_end_of_previous_excerpt(
13872        &mut self,
13873        _: &MoveToEndOfPreviousExcerpt,
13874        window: &mut Window,
13875        cx: &mut Context<Self>,
13876    ) {
13877        if matches!(self.mode, EditorMode::SingleLine) {
13878            cx.propagate();
13879            return;
13880        }
13881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13882        self.change_selections(Default::default(), window, cx, |s| {
13883            s.move_with(|map, selection| {
13884                selection.collapse_to(
13885                    movement::end_of_excerpt(
13886                        map,
13887                        selection.head(),
13888                        workspace::searchable::Direction::Prev,
13889                    ),
13890                    SelectionGoal::None,
13891                )
13892            });
13893        })
13894    }
13895
13896    pub fn select_to_start_of_excerpt(
13897        &mut self,
13898        _: &SelectToStartOfExcerpt,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        if matches!(self.mode, EditorMode::SingleLine) {
13903            cx.propagate();
13904            return;
13905        }
13906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13907        self.change_selections(Default::default(), window, cx, |s| {
13908            s.move_heads_with(|map, head, _| {
13909                (
13910                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13911                    SelectionGoal::None,
13912                )
13913            });
13914        })
13915    }
13916
13917    pub fn select_to_start_of_next_excerpt(
13918        &mut self,
13919        _: &SelectToStartOfNextExcerpt,
13920        window: &mut Window,
13921        cx: &mut Context<Self>,
13922    ) {
13923        if matches!(self.mode, EditorMode::SingleLine) {
13924            cx.propagate();
13925            return;
13926        }
13927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13928        self.change_selections(Default::default(), window, cx, |s| {
13929            s.move_heads_with(|map, head, _| {
13930                (
13931                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13932                    SelectionGoal::None,
13933                )
13934            });
13935        })
13936    }
13937
13938    pub fn select_to_end_of_excerpt(
13939        &mut self,
13940        _: &SelectToEndOfExcerpt,
13941        window: &mut Window,
13942        cx: &mut Context<Self>,
13943    ) {
13944        if matches!(self.mode, EditorMode::SingleLine) {
13945            cx.propagate();
13946            return;
13947        }
13948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13949        self.change_selections(Default::default(), window, cx, |s| {
13950            s.move_heads_with(|map, head, _| {
13951                (
13952                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13953                    SelectionGoal::None,
13954                )
13955            });
13956        })
13957    }
13958
13959    pub fn select_to_end_of_previous_excerpt(
13960        &mut self,
13961        _: &SelectToEndOfPreviousExcerpt,
13962        window: &mut Window,
13963        cx: &mut Context<Self>,
13964    ) {
13965        if matches!(self.mode, EditorMode::SingleLine) {
13966            cx.propagate();
13967            return;
13968        }
13969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13970        self.change_selections(Default::default(), window, cx, |s| {
13971            s.move_heads_with(|map, head, _| {
13972                (
13973                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13974                    SelectionGoal::None,
13975                )
13976            });
13977        })
13978    }
13979
13980    pub fn move_to_beginning(
13981        &mut self,
13982        _: &MoveToBeginning,
13983        window: &mut Window,
13984        cx: &mut Context<Self>,
13985    ) {
13986        if matches!(self.mode, EditorMode::SingleLine) {
13987            cx.propagate();
13988            return;
13989        }
13990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13991        self.change_selections(Default::default(), window, cx, |s| {
13992            s.select_ranges(vec![0..0]);
13993        });
13994    }
13995
13996    pub fn select_to_beginning(
13997        &mut self,
13998        _: &SelectToBeginning,
13999        window: &mut Window,
14000        cx: &mut Context<Self>,
14001    ) {
14002        let mut selection = self.selections.last::<Point>(cx);
14003        selection.set_head(Point::zero(), SelectionGoal::None);
14004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14005        self.change_selections(Default::default(), window, cx, |s| {
14006            s.select(vec![selection]);
14007        });
14008    }
14009
14010    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14011        if matches!(self.mode, EditorMode::SingleLine) {
14012            cx.propagate();
14013            return;
14014        }
14015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14016        let cursor = self.buffer.read(cx).read(cx).len();
14017        self.change_selections(Default::default(), window, cx, |s| {
14018            s.select_ranges(vec![cursor..cursor])
14019        });
14020    }
14021
14022    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14023        self.nav_history = nav_history;
14024    }
14025
14026    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14027        self.nav_history.as_ref()
14028    }
14029
14030    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14031        self.push_to_nav_history(
14032            self.selections.newest_anchor().head(),
14033            None,
14034            false,
14035            true,
14036            cx,
14037        );
14038    }
14039
14040    fn push_to_nav_history(
14041        &mut self,
14042        cursor_anchor: Anchor,
14043        new_position: Option<Point>,
14044        is_deactivate: bool,
14045        always: bool,
14046        cx: &mut Context<Self>,
14047    ) {
14048        if let Some(nav_history) = self.nav_history.as_mut() {
14049            let buffer = self.buffer.read(cx).read(cx);
14050            let cursor_position = cursor_anchor.to_point(&buffer);
14051            let scroll_state = self.scroll_manager.anchor();
14052            let scroll_top_row = scroll_state.top_row(&buffer);
14053            drop(buffer);
14054
14055            if let Some(new_position) = new_position {
14056                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14057                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14058                    return;
14059                }
14060            }
14061
14062            nav_history.push(
14063                Some(NavigationData {
14064                    cursor_anchor,
14065                    cursor_position,
14066                    scroll_anchor: scroll_state,
14067                    scroll_top_row,
14068                }),
14069                cx,
14070            );
14071            cx.emit(EditorEvent::PushedToNavHistory {
14072                anchor: cursor_anchor,
14073                is_deactivate,
14074            })
14075        }
14076    }
14077
14078    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14080        let buffer = self.buffer.read(cx).snapshot(cx);
14081        let mut selection = self.selections.first::<usize>(cx);
14082        selection.set_head(buffer.len(), SelectionGoal::None);
14083        self.change_selections(Default::default(), window, cx, |s| {
14084            s.select(vec![selection]);
14085        });
14086    }
14087
14088    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14090        let end = self.buffer.read(cx).read(cx).len();
14091        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14092            s.select_ranges(vec![0..end]);
14093        });
14094    }
14095
14096    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14097        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14098        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14099        let mut selections = self.selections.all::<Point>(cx);
14100        let max_point = display_map.buffer_snapshot().max_point();
14101        for selection in &mut selections {
14102            let rows = selection.spanned_rows(true, &display_map);
14103            selection.start = Point::new(rows.start.0, 0);
14104            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14105            selection.reversed = false;
14106        }
14107        self.change_selections(Default::default(), window, cx, |s| {
14108            s.select(selections);
14109        });
14110    }
14111
14112    pub fn split_selection_into_lines(
14113        &mut self,
14114        action: &SplitSelectionIntoLines,
14115        window: &mut Window,
14116        cx: &mut Context<Self>,
14117    ) {
14118        let selections = self
14119            .selections
14120            .all::<Point>(cx)
14121            .into_iter()
14122            .map(|selection| selection.start..selection.end)
14123            .collect::<Vec<_>>();
14124        self.unfold_ranges(&selections, true, true, cx);
14125
14126        let mut new_selection_ranges = Vec::new();
14127        {
14128            let buffer = self.buffer.read(cx).read(cx);
14129            for selection in selections {
14130                for row in selection.start.row..selection.end.row {
14131                    let line_start = Point::new(row, 0);
14132                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14133
14134                    if action.keep_selections {
14135                        // Keep the selection range for each line
14136                        let selection_start = if row == selection.start.row {
14137                            selection.start
14138                        } else {
14139                            line_start
14140                        };
14141                        new_selection_ranges.push(selection_start..line_end);
14142                    } else {
14143                        // Collapse to cursor at end of line
14144                        new_selection_ranges.push(line_end..line_end);
14145                    }
14146                }
14147
14148                let is_multiline_selection = selection.start.row != selection.end.row;
14149                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14150                // so this action feels more ergonomic when paired with other selection operations
14151                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14152                if !should_skip_last {
14153                    if action.keep_selections {
14154                        if is_multiline_selection {
14155                            let line_start = Point::new(selection.end.row, 0);
14156                            new_selection_ranges.push(line_start..selection.end);
14157                        } else {
14158                            new_selection_ranges.push(selection.start..selection.end);
14159                        }
14160                    } else {
14161                        new_selection_ranges.push(selection.end..selection.end);
14162                    }
14163                }
14164            }
14165        }
14166        self.change_selections(Default::default(), window, cx, |s| {
14167            s.select_ranges(new_selection_ranges);
14168        });
14169    }
14170
14171    pub fn add_selection_above(
14172        &mut self,
14173        _: &AddSelectionAbove,
14174        window: &mut Window,
14175        cx: &mut Context<Self>,
14176    ) {
14177        self.add_selection(true, window, cx);
14178    }
14179
14180    pub fn add_selection_below(
14181        &mut self,
14182        _: &AddSelectionBelow,
14183        window: &mut Window,
14184        cx: &mut Context<Self>,
14185    ) {
14186        self.add_selection(false, window, cx);
14187    }
14188
14189    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14191
14192        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14193        let all_selections = self.selections.all::<Point>(cx);
14194        let text_layout_details = self.text_layout_details(window);
14195
14196        let (mut columnar_selections, new_selections_to_columnarize) = {
14197            if let Some(state) = self.add_selections_state.as_ref() {
14198                let columnar_selection_ids: HashSet<_> = state
14199                    .groups
14200                    .iter()
14201                    .flat_map(|group| group.stack.iter())
14202                    .copied()
14203                    .collect();
14204
14205                all_selections
14206                    .into_iter()
14207                    .partition(|s| columnar_selection_ids.contains(&s.id))
14208            } else {
14209                (Vec::new(), all_selections)
14210            }
14211        };
14212
14213        let mut state = self
14214            .add_selections_state
14215            .take()
14216            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14217
14218        for selection in new_selections_to_columnarize {
14219            let range = selection.display_range(&display_map).sorted();
14220            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14221            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14222            let positions = start_x.min(end_x)..start_x.max(end_x);
14223            let mut stack = Vec::new();
14224            for row in range.start.row().0..=range.end.row().0 {
14225                if let Some(selection) = self.selections.build_columnar_selection(
14226                    &display_map,
14227                    DisplayRow(row),
14228                    &positions,
14229                    selection.reversed,
14230                    &text_layout_details,
14231                ) {
14232                    stack.push(selection.id);
14233                    columnar_selections.push(selection);
14234                }
14235            }
14236            if !stack.is_empty() {
14237                if above {
14238                    stack.reverse();
14239                }
14240                state.groups.push(AddSelectionsGroup { above, stack });
14241            }
14242        }
14243
14244        let mut final_selections = Vec::new();
14245        let end_row = if above {
14246            DisplayRow(0)
14247        } else {
14248            display_map.max_point().row()
14249        };
14250
14251        let mut last_added_item_per_group = HashMap::default();
14252        for group in state.groups.iter_mut() {
14253            if let Some(last_id) = group.stack.last() {
14254                last_added_item_per_group.insert(*last_id, group);
14255            }
14256        }
14257
14258        for selection in columnar_selections {
14259            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14260                if above == group.above {
14261                    let range = selection.display_range(&display_map).sorted();
14262                    debug_assert_eq!(range.start.row(), range.end.row());
14263                    let mut row = range.start.row();
14264                    let positions =
14265                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14266                            Pixels::from(start)..Pixels::from(end)
14267                        } else {
14268                            let start_x =
14269                                display_map.x_for_display_point(range.start, &text_layout_details);
14270                            let end_x =
14271                                display_map.x_for_display_point(range.end, &text_layout_details);
14272                            start_x.min(end_x)..start_x.max(end_x)
14273                        };
14274
14275                    let mut maybe_new_selection = None;
14276                    while row != end_row {
14277                        if above {
14278                            row.0 -= 1;
14279                        } else {
14280                            row.0 += 1;
14281                        }
14282                        if let Some(new_selection) = self.selections.build_columnar_selection(
14283                            &display_map,
14284                            row,
14285                            &positions,
14286                            selection.reversed,
14287                            &text_layout_details,
14288                        ) {
14289                            maybe_new_selection = Some(new_selection);
14290                            break;
14291                        }
14292                    }
14293
14294                    if let Some(new_selection) = maybe_new_selection {
14295                        group.stack.push(new_selection.id);
14296                        if above {
14297                            final_selections.push(new_selection);
14298                            final_selections.push(selection);
14299                        } else {
14300                            final_selections.push(selection);
14301                            final_selections.push(new_selection);
14302                        }
14303                    } else {
14304                        final_selections.push(selection);
14305                    }
14306                } else {
14307                    group.stack.pop();
14308                }
14309            } else {
14310                final_selections.push(selection);
14311            }
14312        }
14313
14314        self.change_selections(Default::default(), window, cx, |s| {
14315            s.select(final_selections);
14316        });
14317
14318        let final_selection_ids: HashSet<_> = self
14319            .selections
14320            .all::<Point>(cx)
14321            .iter()
14322            .map(|s| s.id)
14323            .collect();
14324        state.groups.retain_mut(|group| {
14325            // selections might get merged above so we remove invalid items from stacks
14326            group.stack.retain(|id| final_selection_ids.contains(id));
14327
14328            // single selection in stack can be treated as initial state
14329            group.stack.len() > 1
14330        });
14331
14332        if !state.groups.is_empty() {
14333            self.add_selections_state = Some(state);
14334        }
14335    }
14336
14337    fn select_match_ranges(
14338        &mut self,
14339        range: Range<usize>,
14340        reversed: bool,
14341        replace_newest: bool,
14342        auto_scroll: Option<Autoscroll>,
14343        window: &mut Window,
14344        cx: &mut Context<Editor>,
14345    ) {
14346        self.unfold_ranges(
14347            std::slice::from_ref(&range),
14348            false,
14349            auto_scroll.is_some(),
14350            cx,
14351        );
14352        let effects = if let Some(scroll) = auto_scroll {
14353            SelectionEffects::scroll(scroll)
14354        } else {
14355            SelectionEffects::no_scroll()
14356        };
14357        self.change_selections(effects, window, cx, |s| {
14358            if replace_newest {
14359                s.delete(s.newest_anchor().id);
14360            }
14361            if reversed {
14362                s.insert_range(range.end..range.start);
14363            } else {
14364                s.insert_range(range);
14365            }
14366        });
14367    }
14368
14369    pub fn select_next_match_internal(
14370        &mut self,
14371        display_map: &DisplaySnapshot,
14372        replace_newest: bool,
14373        autoscroll: Option<Autoscroll>,
14374        window: &mut Window,
14375        cx: &mut Context<Self>,
14376    ) -> Result<()> {
14377        let buffer = display_map.buffer_snapshot();
14378        let mut selections = self.selections.all::<usize>(cx);
14379        if let Some(mut select_next_state) = self.select_next_state.take() {
14380            let query = &select_next_state.query;
14381            if !select_next_state.done {
14382                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14383                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14384                let mut next_selected_range = None;
14385
14386                let bytes_after_last_selection =
14387                    buffer.bytes_in_range(last_selection.end..buffer.len());
14388                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14389                let query_matches = query
14390                    .stream_find_iter(bytes_after_last_selection)
14391                    .map(|result| (last_selection.end, result))
14392                    .chain(
14393                        query
14394                            .stream_find_iter(bytes_before_first_selection)
14395                            .map(|result| (0, result)),
14396                    );
14397
14398                for (start_offset, query_match) in query_matches {
14399                    let query_match = query_match.unwrap(); // can only fail due to I/O
14400                    let offset_range =
14401                        start_offset + query_match.start()..start_offset + query_match.end();
14402
14403                    if !select_next_state.wordwise
14404                        || (!buffer.is_inside_word(offset_range.start, None)
14405                            && !buffer.is_inside_word(offset_range.end, None))
14406                    {
14407                        // TODO: This is n^2, because we might check all the selections
14408                        if !selections
14409                            .iter()
14410                            .any(|selection| selection.range().overlaps(&offset_range))
14411                        {
14412                            next_selected_range = Some(offset_range);
14413                            break;
14414                        }
14415                    }
14416                }
14417
14418                if let Some(next_selected_range) = next_selected_range {
14419                    self.select_match_ranges(
14420                        next_selected_range,
14421                        last_selection.reversed,
14422                        replace_newest,
14423                        autoscroll,
14424                        window,
14425                        cx,
14426                    );
14427                } else {
14428                    select_next_state.done = true;
14429                }
14430            }
14431
14432            self.select_next_state = Some(select_next_state);
14433        } else {
14434            let mut only_carets = true;
14435            let mut same_text_selected = true;
14436            let mut selected_text = None;
14437
14438            let mut selections_iter = selections.iter().peekable();
14439            while let Some(selection) = selections_iter.next() {
14440                if selection.start != selection.end {
14441                    only_carets = false;
14442                }
14443
14444                if same_text_selected {
14445                    if selected_text.is_none() {
14446                        selected_text =
14447                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14448                    }
14449
14450                    if let Some(next_selection) = selections_iter.peek() {
14451                        if next_selection.range().len() == selection.range().len() {
14452                            let next_selected_text = buffer
14453                                .text_for_range(next_selection.range())
14454                                .collect::<String>();
14455                            if Some(next_selected_text) != selected_text {
14456                                same_text_selected = false;
14457                                selected_text = None;
14458                            }
14459                        } else {
14460                            same_text_selected = false;
14461                            selected_text = None;
14462                        }
14463                    }
14464                }
14465            }
14466
14467            if only_carets {
14468                for selection in &mut selections {
14469                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14470                    selection.start = word_range.start;
14471                    selection.end = word_range.end;
14472                    selection.goal = SelectionGoal::None;
14473                    selection.reversed = false;
14474                    self.select_match_ranges(
14475                        selection.start..selection.end,
14476                        selection.reversed,
14477                        replace_newest,
14478                        autoscroll,
14479                        window,
14480                        cx,
14481                    );
14482                }
14483
14484                if selections.len() == 1 {
14485                    let selection = selections
14486                        .last()
14487                        .expect("ensured that there's only one selection");
14488                    let query = buffer
14489                        .text_for_range(selection.start..selection.end)
14490                        .collect::<String>();
14491                    let is_empty = query.is_empty();
14492                    let select_state = SelectNextState {
14493                        query: AhoCorasick::new(&[query])?,
14494                        wordwise: true,
14495                        done: is_empty,
14496                    };
14497                    self.select_next_state = Some(select_state);
14498                } else {
14499                    self.select_next_state = None;
14500                }
14501            } else if let Some(selected_text) = selected_text {
14502                self.select_next_state = Some(SelectNextState {
14503                    query: AhoCorasick::new(&[selected_text])?,
14504                    wordwise: false,
14505                    done: false,
14506                });
14507                self.select_next_match_internal(
14508                    display_map,
14509                    replace_newest,
14510                    autoscroll,
14511                    window,
14512                    cx,
14513                )?;
14514            }
14515        }
14516        Ok(())
14517    }
14518
14519    pub fn select_all_matches(
14520        &mut self,
14521        _action: &SelectAllMatches,
14522        window: &mut Window,
14523        cx: &mut Context<Self>,
14524    ) -> Result<()> {
14525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14526
14527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14528
14529        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14530        let Some(select_next_state) = self.select_next_state.as_mut() else {
14531            return Ok(());
14532        };
14533        if select_next_state.done {
14534            return Ok(());
14535        }
14536
14537        let mut new_selections = Vec::new();
14538
14539        let reversed = self.selections.oldest::<usize>(cx).reversed;
14540        let buffer = display_map.buffer_snapshot();
14541        let query_matches = select_next_state
14542            .query
14543            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14544
14545        for query_match in query_matches.into_iter() {
14546            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14547            let offset_range = if reversed {
14548                query_match.end()..query_match.start()
14549            } else {
14550                query_match.start()..query_match.end()
14551            };
14552
14553            if !select_next_state.wordwise
14554                || (!buffer.is_inside_word(offset_range.start, None)
14555                    && !buffer.is_inside_word(offset_range.end, None))
14556            {
14557                new_selections.push(offset_range.start..offset_range.end);
14558            }
14559        }
14560
14561        select_next_state.done = true;
14562
14563        if new_selections.is_empty() {
14564            log::error!("bug: new_selections is empty in select_all_matches");
14565            return Ok(());
14566        }
14567
14568        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14569        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14570            selections.select_ranges(new_selections)
14571        });
14572
14573        Ok(())
14574    }
14575
14576    pub fn select_next(
14577        &mut self,
14578        action: &SelectNext,
14579        window: &mut Window,
14580        cx: &mut Context<Self>,
14581    ) -> Result<()> {
14582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14584        self.select_next_match_internal(
14585            &display_map,
14586            action.replace_newest,
14587            Some(Autoscroll::newest()),
14588            window,
14589            cx,
14590        )?;
14591        Ok(())
14592    }
14593
14594    pub fn select_previous(
14595        &mut self,
14596        action: &SelectPrevious,
14597        window: &mut Window,
14598        cx: &mut Context<Self>,
14599    ) -> Result<()> {
14600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14602        let buffer = display_map.buffer_snapshot();
14603        let mut selections = self.selections.all::<usize>(cx);
14604        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14605            let query = &select_prev_state.query;
14606            if !select_prev_state.done {
14607                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14608                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14609                let mut next_selected_range = None;
14610                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14611                let bytes_before_last_selection =
14612                    buffer.reversed_bytes_in_range(0..last_selection.start);
14613                let bytes_after_first_selection =
14614                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14615                let query_matches = query
14616                    .stream_find_iter(bytes_before_last_selection)
14617                    .map(|result| (last_selection.start, result))
14618                    .chain(
14619                        query
14620                            .stream_find_iter(bytes_after_first_selection)
14621                            .map(|result| (buffer.len(), result)),
14622                    );
14623                for (end_offset, query_match) in query_matches {
14624                    let query_match = query_match.unwrap(); // can only fail due to I/O
14625                    let offset_range =
14626                        end_offset - query_match.end()..end_offset - query_match.start();
14627
14628                    if !select_prev_state.wordwise
14629                        || (!buffer.is_inside_word(offset_range.start, None)
14630                            && !buffer.is_inside_word(offset_range.end, None))
14631                    {
14632                        next_selected_range = Some(offset_range);
14633                        break;
14634                    }
14635                }
14636
14637                if let Some(next_selected_range) = next_selected_range {
14638                    self.select_match_ranges(
14639                        next_selected_range,
14640                        last_selection.reversed,
14641                        action.replace_newest,
14642                        Some(Autoscroll::newest()),
14643                        window,
14644                        cx,
14645                    );
14646                } else {
14647                    select_prev_state.done = true;
14648                }
14649            }
14650
14651            self.select_prev_state = Some(select_prev_state);
14652        } else {
14653            let mut only_carets = true;
14654            let mut same_text_selected = true;
14655            let mut selected_text = None;
14656
14657            let mut selections_iter = selections.iter().peekable();
14658            while let Some(selection) = selections_iter.next() {
14659                if selection.start != selection.end {
14660                    only_carets = false;
14661                }
14662
14663                if same_text_selected {
14664                    if selected_text.is_none() {
14665                        selected_text =
14666                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14667                    }
14668
14669                    if let Some(next_selection) = selections_iter.peek() {
14670                        if next_selection.range().len() == selection.range().len() {
14671                            let next_selected_text = buffer
14672                                .text_for_range(next_selection.range())
14673                                .collect::<String>();
14674                            if Some(next_selected_text) != selected_text {
14675                                same_text_selected = false;
14676                                selected_text = None;
14677                            }
14678                        } else {
14679                            same_text_selected = false;
14680                            selected_text = None;
14681                        }
14682                    }
14683                }
14684            }
14685
14686            if only_carets {
14687                for selection in &mut selections {
14688                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14689                    selection.start = word_range.start;
14690                    selection.end = word_range.end;
14691                    selection.goal = SelectionGoal::None;
14692                    selection.reversed = false;
14693                    self.select_match_ranges(
14694                        selection.start..selection.end,
14695                        selection.reversed,
14696                        action.replace_newest,
14697                        Some(Autoscroll::newest()),
14698                        window,
14699                        cx,
14700                    );
14701                }
14702                if selections.len() == 1 {
14703                    let selection = selections
14704                        .last()
14705                        .expect("ensured that there's only one selection");
14706                    let query = buffer
14707                        .text_for_range(selection.start..selection.end)
14708                        .collect::<String>();
14709                    let is_empty = query.is_empty();
14710                    let select_state = SelectNextState {
14711                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14712                        wordwise: true,
14713                        done: is_empty,
14714                    };
14715                    self.select_prev_state = Some(select_state);
14716                } else {
14717                    self.select_prev_state = None;
14718                }
14719            } else if let Some(selected_text) = selected_text {
14720                self.select_prev_state = Some(SelectNextState {
14721                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14722                    wordwise: false,
14723                    done: false,
14724                });
14725                self.select_previous(action, window, cx)?;
14726            }
14727        }
14728        Ok(())
14729    }
14730
14731    pub fn find_next_match(
14732        &mut self,
14733        _: &FindNextMatch,
14734        window: &mut Window,
14735        cx: &mut Context<Self>,
14736    ) -> Result<()> {
14737        let selections = self.selections.disjoint_anchors_arc();
14738        match selections.first() {
14739            Some(first) if selections.len() >= 2 => {
14740                self.change_selections(Default::default(), window, cx, |s| {
14741                    s.select_ranges([first.range()]);
14742                });
14743            }
14744            _ => self.select_next(
14745                &SelectNext {
14746                    replace_newest: true,
14747                },
14748                window,
14749                cx,
14750            )?,
14751        }
14752        Ok(())
14753    }
14754
14755    pub fn find_previous_match(
14756        &mut self,
14757        _: &FindPreviousMatch,
14758        window: &mut Window,
14759        cx: &mut Context<Self>,
14760    ) -> Result<()> {
14761        let selections = self.selections.disjoint_anchors_arc();
14762        match selections.last() {
14763            Some(last) if selections.len() >= 2 => {
14764                self.change_selections(Default::default(), window, cx, |s| {
14765                    s.select_ranges([last.range()]);
14766                });
14767            }
14768            _ => self.select_previous(
14769                &SelectPrevious {
14770                    replace_newest: true,
14771                },
14772                window,
14773                cx,
14774            )?,
14775        }
14776        Ok(())
14777    }
14778
14779    pub fn toggle_comments(
14780        &mut self,
14781        action: &ToggleComments,
14782        window: &mut Window,
14783        cx: &mut Context<Self>,
14784    ) {
14785        if self.read_only(cx) {
14786            return;
14787        }
14788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14789        let text_layout_details = &self.text_layout_details(window);
14790        self.transact(window, cx, |this, window, cx| {
14791            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14792            let mut edits = Vec::new();
14793            let mut selection_edit_ranges = Vec::new();
14794            let mut last_toggled_row = None;
14795            let snapshot = this.buffer.read(cx).read(cx);
14796            let empty_str: Arc<str> = Arc::default();
14797            let mut suffixes_inserted = Vec::new();
14798            let ignore_indent = action.ignore_indent;
14799
14800            fn comment_prefix_range(
14801                snapshot: &MultiBufferSnapshot,
14802                row: MultiBufferRow,
14803                comment_prefix: &str,
14804                comment_prefix_whitespace: &str,
14805                ignore_indent: bool,
14806            ) -> Range<Point> {
14807                let indent_size = if ignore_indent {
14808                    0
14809                } else {
14810                    snapshot.indent_size_for_line(row).len
14811                };
14812
14813                let start = Point::new(row.0, indent_size);
14814
14815                let mut line_bytes = snapshot
14816                    .bytes_in_range(start..snapshot.max_point())
14817                    .flatten()
14818                    .copied();
14819
14820                // If this line currently begins with the line comment prefix, then record
14821                // the range containing the prefix.
14822                if line_bytes
14823                    .by_ref()
14824                    .take(comment_prefix.len())
14825                    .eq(comment_prefix.bytes())
14826                {
14827                    // Include any whitespace that matches the comment prefix.
14828                    let matching_whitespace_len = line_bytes
14829                        .zip(comment_prefix_whitespace.bytes())
14830                        .take_while(|(a, b)| a == b)
14831                        .count() as u32;
14832                    let end = Point::new(
14833                        start.row,
14834                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14835                    );
14836                    start..end
14837                } else {
14838                    start..start
14839                }
14840            }
14841
14842            fn comment_suffix_range(
14843                snapshot: &MultiBufferSnapshot,
14844                row: MultiBufferRow,
14845                comment_suffix: &str,
14846                comment_suffix_has_leading_space: bool,
14847            ) -> Range<Point> {
14848                let end = Point::new(row.0, snapshot.line_len(row));
14849                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14850
14851                let mut line_end_bytes = snapshot
14852                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14853                    .flatten()
14854                    .copied();
14855
14856                let leading_space_len = if suffix_start_column > 0
14857                    && line_end_bytes.next() == Some(b' ')
14858                    && comment_suffix_has_leading_space
14859                {
14860                    1
14861                } else {
14862                    0
14863                };
14864
14865                // If this line currently begins with the line comment prefix, then record
14866                // the range containing the prefix.
14867                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14868                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14869                    start..end
14870                } else {
14871                    end..end
14872                }
14873            }
14874
14875            // TODO: Handle selections that cross excerpts
14876            for selection in &mut selections {
14877                let start_column = snapshot
14878                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14879                    .len;
14880                let language = if let Some(language) =
14881                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14882                {
14883                    language
14884                } else {
14885                    continue;
14886                };
14887
14888                selection_edit_ranges.clear();
14889
14890                // If multiple selections contain a given row, avoid processing that
14891                // row more than once.
14892                let mut start_row = MultiBufferRow(selection.start.row);
14893                if last_toggled_row == Some(start_row) {
14894                    start_row = start_row.next_row();
14895                }
14896                let end_row =
14897                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14898                        MultiBufferRow(selection.end.row - 1)
14899                    } else {
14900                        MultiBufferRow(selection.end.row)
14901                    };
14902                last_toggled_row = Some(end_row);
14903
14904                if start_row > end_row {
14905                    continue;
14906                }
14907
14908                // If the language has line comments, toggle those.
14909                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14910
14911                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14912                if ignore_indent {
14913                    full_comment_prefixes = full_comment_prefixes
14914                        .into_iter()
14915                        .map(|s| Arc::from(s.trim_end()))
14916                        .collect();
14917                }
14918
14919                if !full_comment_prefixes.is_empty() {
14920                    let first_prefix = full_comment_prefixes
14921                        .first()
14922                        .expect("prefixes is non-empty");
14923                    let prefix_trimmed_lengths = full_comment_prefixes
14924                        .iter()
14925                        .map(|p| p.trim_end_matches(' ').len())
14926                        .collect::<SmallVec<[usize; 4]>>();
14927
14928                    let mut all_selection_lines_are_comments = true;
14929
14930                    for row in start_row.0..=end_row.0 {
14931                        let row = MultiBufferRow(row);
14932                        if start_row < end_row && snapshot.is_line_blank(row) {
14933                            continue;
14934                        }
14935
14936                        let prefix_range = full_comment_prefixes
14937                            .iter()
14938                            .zip(prefix_trimmed_lengths.iter().copied())
14939                            .map(|(prefix, trimmed_prefix_len)| {
14940                                comment_prefix_range(
14941                                    snapshot.deref(),
14942                                    row,
14943                                    &prefix[..trimmed_prefix_len],
14944                                    &prefix[trimmed_prefix_len..],
14945                                    ignore_indent,
14946                                )
14947                            })
14948                            .max_by_key(|range| range.end.column - range.start.column)
14949                            .expect("prefixes is non-empty");
14950
14951                        if prefix_range.is_empty() {
14952                            all_selection_lines_are_comments = false;
14953                        }
14954
14955                        selection_edit_ranges.push(prefix_range);
14956                    }
14957
14958                    if all_selection_lines_are_comments {
14959                        edits.extend(
14960                            selection_edit_ranges
14961                                .iter()
14962                                .cloned()
14963                                .map(|range| (range, empty_str.clone())),
14964                        );
14965                    } else {
14966                        let min_column = selection_edit_ranges
14967                            .iter()
14968                            .map(|range| range.start.column)
14969                            .min()
14970                            .unwrap_or(0);
14971                        edits.extend(selection_edit_ranges.iter().map(|range| {
14972                            let position = Point::new(range.start.row, min_column);
14973                            (position..position, first_prefix.clone())
14974                        }));
14975                    }
14976                } else if let Some(BlockCommentConfig {
14977                    start: full_comment_prefix,
14978                    end: comment_suffix,
14979                    ..
14980                }) = language.block_comment()
14981                {
14982                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14983                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14984                    let prefix_range = comment_prefix_range(
14985                        snapshot.deref(),
14986                        start_row,
14987                        comment_prefix,
14988                        comment_prefix_whitespace,
14989                        ignore_indent,
14990                    );
14991                    let suffix_range = comment_suffix_range(
14992                        snapshot.deref(),
14993                        end_row,
14994                        comment_suffix.trim_start_matches(' '),
14995                        comment_suffix.starts_with(' '),
14996                    );
14997
14998                    if prefix_range.is_empty() || suffix_range.is_empty() {
14999                        edits.push((
15000                            prefix_range.start..prefix_range.start,
15001                            full_comment_prefix.clone(),
15002                        ));
15003                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15004                        suffixes_inserted.push((end_row, comment_suffix.len()));
15005                    } else {
15006                        edits.push((prefix_range, empty_str.clone()));
15007                        edits.push((suffix_range, empty_str.clone()));
15008                    }
15009                } else {
15010                    continue;
15011                }
15012            }
15013
15014            drop(snapshot);
15015            this.buffer.update(cx, |buffer, cx| {
15016                buffer.edit(edits, None, cx);
15017            });
15018
15019            // Adjust selections so that they end before any comment suffixes that
15020            // were inserted.
15021            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15022            let mut selections = this.selections.all::<Point>(cx);
15023            let snapshot = this.buffer.read(cx).read(cx);
15024            for selection in &mut selections {
15025                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15026                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15027                        Ordering::Less => {
15028                            suffixes_inserted.next();
15029                            continue;
15030                        }
15031                        Ordering::Greater => break,
15032                        Ordering::Equal => {
15033                            if selection.end.column == snapshot.line_len(row) {
15034                                if selection.is_empty() {
15035                                    selection.start.column -= suffix_len as u32;
15036                                }
15037                                selection.end.column -= suffix_len as u32;
15038                            }
15039                            break;
15040                        }
15041                    }
15042                }
15043            }
15044
15045            drop(snapshot);
15046            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15047
15048            let selections = this.selections.all::<Point>(cx);
15049            let selections_on_single_row = selections.windows(2).all(|selections| {
15050                selections[0].start.row == selections[1].start.row
15051                    && selections[0].end.row == selections[1].end.row
15052                    && selections[0].start.row == selections[0].end.row
15053            });
15054            let selections_selecting = selections
15055                .iter()
15056                .any(|selection| selection.start != selection.end);
15057            let advance_downwards = action.advance_downwards
15058                && selections_on_single_row
15059                && !selections_selecting
15060                && !matches!(this.mode, EditorMode::SingleLine);
15061
15062            if advance_downwards {
15063                let snapshot = this.buffer.read(cx).snapshot(cx);
15064
15065                this.change_selections(Default::default(), window, cx, |s| {
15066                    s.move_cursors_with(|display_snapshot, display_point, _| {
15067                        let mut point = display_point.to_point(display_snapshot);
15068                        point.row += 1;
15069                        point = snapshot.clip_point(point, Bias::Left);
15070                        let display_point = point.to_display_point(display_snapshot);
15071                        let goal = SelectionGoal::HorizontalPosition(
15072                            display_snapshot
15073                                .x_for_display_point(display_point, text_layout_details)
15074                                .into(),
15075                        );
15076                        (display_point, goal)
15077                    })
15078                });
15079            }
15080        });
15081    }
15082
15083    pub fn select_enclosing_symbol(
15084        &mut self,
15085        _: &SelectEnclosingSymbol,
15086        window: &mut Window,
15087        cx: &mut Context<Self>,
15088    ) {
15089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15090
15091        let buffer = self.buffer.read(cx).snapshot(cx);
15092        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15093
15094        fn update_selection(
15095            selection: &Selection<usize>,
15096            buffer_snap: &MultiBufferSnapshot,
15097        ) -> Option<Selection<usize>> {
15098            let cursor = selection.head();
15099            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15100            for symbol in symbols.iter().rev() {
15101                let start = symbol.range.start.to_offset(buffer_snap);
15102                let end = symbol.range.end.to_offset(buffer_snap);
15103                let new_range = start..end;
15104                if start < selection.start || end > selection.end {
15105                    return Some(Selection {
15106                        id: selection.id,
15107                        start: new_range.start,
15108                        end: new_range.end,
15109                        goal: SelectionGoal::None,
15110                        reversed: selection.reversed,
15111                    });
15112                }
15113            }
15114            None
15115        }
15116
15117        let mut selected_larger_symbol = false;
15118        let new_selections = old_selections
15119            .iter()
15120            .map(|selection| match update_selection(selection, &buffer) {
15121                Some(new_selection) => {
15122                    if new_selection.range() != selection.range() {
15123                        selected_larger_symbol = true;
15124                    }
15125                    new_selection
15126                }
15127                None => selection.clone(),
15128            })
15129            .collect::<Vec<_>>();
15130
15131        if selected_larger_symbol {
15132            self.change_selections(Default::default(), window, cx, |s| {
15133                s.select(new_selections);
15134            });
15135        }
15136    }
15137
15138    pub fn select_larger_syntax_node(
15139        &mut self,
15140        _: &SelectLargerSyntaxNode,
15141        window: &mut Window,
15142        cx: &mut Context<Self>,
15143    ) {
15144        let Some(visible_row_count) = self.visible_row_count() else {
15145            return;
15146        };
15147        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15148        if old_selections.is_empty() {
15149            return;
15150        }
15151
15152        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15153
15154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15155        let buffer = self.buffer.read(cx).snapshot(cx);
15156
15157        let mut selected_larger_node = false;
15158        let mut new_selections = old_selections
15159            .iter()
15160            .map(|selection| {
15161                let old_range = selection.start..selection.end;
15162
15163                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15164                    // manually select word at selection
15165                    if ["string_content", "inline"].contains(&node.kind()) {
15166                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15167                        // ignore if word is already selected
15168                        if !word_range.is_empty() && old_range != word_range {
15169                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15170                            // only select word if start and end point belongs to same word
15171                            if word_range == last_word_range {
15172                                selected_larger_node = true;
15173                                return Selection {
15174                                    id: selection.id,
15175                                    start: word_range.start,
15176                                    end: word_range.end,
15177                                    goal: SelectionGoal::None,
15178                                    reversed: selection.reversed,
15179                                };
15180                            }
15181                        }
15182                    }
15183                }
15184
15185                let mut new_range = old_range.clone();
15186                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15187                    new_range = range;
15188                    if !node.is_named() {
15189                        continue;
15190                    }
15191                    if !display_map.intersects_fold(new_range.start)
15192                        && !display_map.intersects_fold(new_range.end)
15193                    {
15194                        break;
15195                    }
15196                }
15197
15198                selected_larger_node |= new_range != old_range;
15199                Selection {
15200                    id: selection.id,
15201                    start: new_range.start,
15202                    end: new_range.end,
15203                    goal: SelectionGoal::None,
15204                    reversed: selection.reversed,
15205                }
15206            })
15207            .collect::<Vec<_>>();
15208
15209        if !selected_larger_node {
15210            return; // don't put this call in the history
15211        }
15212
15213        // scroll based on transformation done to the last selection created by the user
15214        let (last_old, last_new) = old_selections
15215            .last()
15216            .zip(new_selections.last().cloned())
15217            .expect("old_selections isn't empty");
15218
15219        // revert selection
15220        let is_selection_reversed = {
15221            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15222            new_selections.last_mut().expect("checked above").reversed =
15223                should_newest_selection_be_reversed;
15224            should_newest_selection_be_reversed
15225        };
15226
15227        if selected_larger_node {
15228            self.select_syntax_node_history.disable_clearing = true;
15229            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15230                s.select(new_selections.clone());
15231            });
15232            self.select_syntax_node_history.disable_clearing = false;
15233        }
15234
15235        let start_row = last_new.start.to_display_point(&display_map).row().0;
15236        let end_row = last_new.end.to_display_point(&display_map).row().0;
15237        let selection_height = end_row - start_row + 1;
15238        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15239
15240        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15241        let scroll_behavior = if fits_on_the_screen {
15242            self.request_autoscroll(Autoscroll::fit(), cx);
15243            SelectSyntaxNodeScrollBehavior::FitSelection
15244        } else if is_selection_reversed {
15245            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15246            SelectSyntaxNodeScrollBehavior::CursorTop
15247        } else {
15248            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15249            SelectSyntaxNodeScrollBehavior::CursorBottom
15250        };
15251
15252        self.select_syntax_node_history.push((
15253            old_selections,
15254            scroll_behavior,
15255            is_selection_reversed,
15256        ));
15257    }
15258
15259    pub fn select_smaller_syntax_node(
15260        &mut self,
15261        _: &SelectSmallerSyntaxNode,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15266
15267        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15268            self.select_syntax_node_history.pop()
15269        {
15270            if let Some(selection) = selections.last_mut() {
15271                selection.reversed = is_selection_reversed;
15272            }
15273
15274            self.select_syntax_node_history.disable_clearing = true;
15275            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15276                s.select(selections.to_vec());
15277            });
15278            self.select_syntax_node_history.disable_clearing = false;
15279
15280            match scroll_behavior {
15281                SelectSyntaxNodeScrollBehavior::CursorTop => {
15282                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15283                }
15284                SelectSyntaxNodeScrollBehavior::FitSelection => {
15285                    self.request_autoscroll(Autoscroll::fit(), cx);
15286                }
15287                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15288                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15289                }
15290            }
15291        }
15292    }
15293
15294    pub fn unwrap_syntax_node(
15295        &mut self,
15296        _: &UnwrapSyntaxNode,
15297        window: &mut Window,
15298        cx: &mut Context<Self>,
15299    ) {
15300        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15301
15302        let buffer = self.buffer.read(cx).snapshot(cx);
15303        let selections = self
15304            .selections
15305            .all::<usize>(cx)
15306            .into_iter()
15307            // subtracting the offset requires sorting
15308            .sorted_by_key(|i| i.start);
15309
15310        let full_edits = selections
15311            .into_iter()
15312            .filter_map(|selection| {
15313                let child = if selection.is_empty()
15314                    && let Some((_, ancestor_range)) =
15315                        buffer.syntax_ancestor(selection.start..selection.end)
15316                {
15317                    ancestor_range
15318                } else {
15319                    selection.range()
15320                };
15321
15322                let mut parent = child.clone();
15323                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15324                    parent = ancestor_range;
15325                    if parent.start < child.start || parent.end > child.end {
15326                        break;
15327                    }
15328                }
15329
15330                if parent == child {
15331                    return None;
15332                }
15333                let text = buffer.text_for_range(child).collect::<String>();
15334                Some((selection.id, parent, text))
15335            })
15336            .collect::<Vec<_>>();
15337        if full_edits.is_empty() {
15338            return;
15339        }
15340
15341        self.transact(window, cx, |this, window, cx| {
15342            this.buffer.update(cx, |buffer, cx| {
15343                buffer.edit(
15344                    full_edits
15345                        .iter()
15346                        .map(|(_, p, t)| (p.clone(), t.clone()))
15347                        .collect::<Vec<_>>(),
15348                    None,
15349                    cx,
15350                );
15351            });
15352            this.change_selections(Default::default(), window, cx, |s| {
15353                let mut offset = 0;
15354                let mut selections = vec![];
15355                for (id, parent, text) in full_edits {
15356                    let start = parent.start - offset;
15357                    offset += parent.len() - text.len();
15358                    selections.push(Selection {
15359                        id,
15360                        start,
15361                        end: start + text.len(),
15362                        reversed: false,
15363                        goal: Default::default(),
15364                    });
15365                }
15366                s.select(selections);
15367            });
15368        });
15369    }
15370
15371    pub fn select_next_syntax_node(
15372        &mut self,
15373        _: &SelectNextSyntaxNode,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) {
15377        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15378        if old_selections.is_empty() {
15379            return;
15380        }
15381
15382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15383
15384        let buffer = self.buffer.read(cx).snapshot(cx);
15385        let mut selected_sibling = false;
15386
15387        let new_selections = old_selections
15388            .iter()
15389            .map(|selection| {
15390                let old_range = selection.start..selection.end;
15391
15392                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15393                    let new_range = node.byte_range();
15394                    selected_sibling = true;
15395                    Selection {
15396                        id: selection.id,
15397                        start: new_range.start,
15398                        end: new_range.end,
15399                        goal: SelectionGoal::None,
15400                        reversed: selection.reversed,
15401                    }
15402                } else {
15403                    selection.clone()
15404                }
15405            })
15406            .collect::<Vec<_>>();
15407
15408        if selected_sibling {
15409            self.change_selections(
15410                SelectionEffects::scroll(Autoscroll::fit()),
15411                window,
15412                cx,
15413                |s| {
15414                    s.select(new_selections);
15415                },
15416            );
15417        }
15418    }
15419
15420    pub fn select_prev_syntax_node(
15421        &mut self,
15422        _: &SelectPreviousSyntaxNode,
15423        window: &mut Window,
15424        cx: &mut Context<Self>,
15425    ) {
15426        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15427        if old_selections.is_empty() {
15428            return;
15429        }
15430
15431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15432
15433        let buffer = self.buffer.read(cx).snapshot(cx);
15434        let mut selected_sibling = false;
15435
15436        let new_selections = old_selections
15437            .iter()
15438            .map(|selection| {
15439                let old_range = selection.start..selection.end;
15440
15441                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15442                    let new_range = node.byte_range();
15443                    selected_sibling = true;
15444                    Selection {
15445                        id: selection.id,
15446                        start: new_range.start,
15447                        end: new_range.end,
15448                        goal: SelectionGoal::None,
15449                        reversed: selection.reversed,
15450                    }
15451                } else {
15452                    selection.clone()
15453                }
15454            })
15455            .collect::<Vec<_>>();
15456
15457        if selected_sibling {
15458            self.change_selections(
15459                SelectionEffects::scroll(Autoscroll::fit()),
15460                window,
15461                cx,
15462                |s| {
15463                    s.select(new_selections);
15464                },
15465            );
15466        }
15467    }
15468
15469    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15470        if !EditorSettings::get_global(cx).gutter.runnables {
15471            self.clear_tasks();
15472            return Task::ready(());
15473        }
15474        let project = self.project().map(Entity::downgrade);
15475        let task_sources = self.lsp_task_sources(cx);
15476        let multi_buffer = self.buffer.downgrade();
15477        cx.spawn_in(window, async move |editor, cx| {
15478            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15479            let Some(project) = project.and_then(|p| p.upgrade()) else {
15480                return;
15481            };
15482            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15483                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15484            }) else {
15485                return;
15486            };
15487
15488            let hide_runnables = project
15489                .update(cx, |project, _| project.is_via_collab())
15490                .unwrap_or(true);
15491            if hide_runnables {
15492                return;
15493            }
15494            let new_rows =
15495                cx.background_spawn({
15496                    let snapshot = display_snapshot.clone();
15497                    async move {
15498                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15499                    }
15500                })
15501                    .await;
15502            let Ok(lsp_tasks) =
15503                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15504            else {
15505                return;
15506            };
15507            let lsp_tasks = lsp_tasks.await;
15508
15509            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15510                lsp_tasks
15511                    .into_iter()
15512                    .flat_map(|(kind, tasks)| {
15513                        tasks.into_iter().filter_map(move |(location, task)| {
15514                            Some((kind.clone(), location?, task))
15515                        })
15516                    })
15517                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15518                        let buffer = location.target.buffer;
15519                        let buffer_snapshot = buffer.read(cx).snapshot();
15520                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15521                            |(excerpt_id, snapshot, _)| {
15522                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15523                                    display_snapshot
15524                                        .buffer_snapshot()
15525                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15526                                } else {
15527                                    None
15528                                }
15529                            },
15530                        );
15531                        if let Some(offset) = offset {
15532                            let task_buffer_range =
15533                                location.target.range.to_point(&buffer_snapshot);
15534                            let context_buffer_range =
15535                                task_buffer_range.to_offset(&buffer_snapshot);
15536                            let context_range = BufferOffset(context_buffer_range.start)
15537                                ..BufferOffset(context_buffer_range.end);
15538
15539                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15540                                .or_insert_with(|| RunnableTasks {
15541                                    templates: Vec::new(),
15542                                    offset,
15543                                    column: task_buffer_range.start.column,
15544                                    extra_variables: HashMap::default(),
15545                                    context_range,
15546                                })
15547                                .templates
15548                                .push((kind, task.original_task().clone()));
15549                        }
15550
15551                        acc
15552                    })
15553            }) else {
15554                return;
15555            };
15556
15557            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15558                buffer.language_settings(cx).tasks.prefer_lsp
15559            }) else {
15560                return;
15561            };
15562
15563            let rows = Self::runnable_rows(
15564                project,
15565                display_snapshot,
15566                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15567                new_rows,
15568                cx.clone(),
15569            )
15570            .await;
15571            editor
15572                .update(cx, |editor, _| {
15573                    editor.clear_tasks();
15574                    for (key, mut value) in rows {
15575                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15576                            value.templates.extend(lsp_tasks.templates);
15577                        }
15578
15579                        editor.insert_tasks(key, value);
15580                    }
15581                    for (key, value) in lsp_tasks_by_rows {
15582                        editor.insert_tasks(key, value);
15583                    }
15584                })
15585                .ok();
15586        })
15587    }
15588    fn fetch_runnable_ranges(
15589        snapshot: &DisplaySnapshot,
15590        range: Range<Anchor>,
15591    ) -> Vec<language::RunnableRange> {
15592        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15593    }
15594
15595    fn runnable_rows(
15596        project: Entity<Project>,
15597        snapshot: DisplaySnapshot,
15598        prefer_lsp: bool,
15599        runnable_ranges: Vec<RunnableRange>,
15600        cx: AsyncWindowContext,
15601    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15602        cx.spawn(async move |cx| {
15603            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15604            for mut runnable in runnable_ranges {
15605                let Some(tasks) = cx
15606                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15607                    .ok()
15608                else {
15609                    continue;
15610                };
15611                let mut tasks = tasks.await;
15612
15613                if prefer_lsp {
15614                    tasks.retain(|(task_kind, _)| {
15615                        !matches!(task_kind, TaskSourceKind::Language { .. })
15616                    });
15617                }
15618                if tasks.is_empty() {
15619                    continue;
15620                }
15621
15622                let point = runnable
15623                    .run_range
15624                    .start
15625                    .to_point(&snapshot.buffer_snapshot());
15626                let Some(row) = snapshot
15627                    .buffer_snapshot()
15628                    .buffer_line_for_row(MultiBufferRow(point.row))
15629                    .map(|(_, range)| range.start.row)
15630                else {
15631                    continue;
15632                };
15633
15634                let context_range =
15635                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15636                runnable_rows.push((
15637                    (runnable.buffer_id, row),
15638                    RunnableTasks {
15639                        templates: tasks,
15640                        offset: snapshot
15641                            .buffer_snapshot()
15642                            .anchor_before(runnable.run_range.start),
15643                        context_range,
15644                        column: point.column,
15645                        extra_variables: runnable.extra_captures,
15646                    },
15647                ));
15648            }
15649            runnable_rows
15650        })
15651    }
15652
15653    fn templates_with_tags(
15654        project: &Entity<Project>,
15655        runnable: &mut Runnable,
15656        cx: &mut App,
15657    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15658        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15659            let (worktree_id, file) = project
15660                .buffer_for_id(runnable.buffer, cx)
15661                .and_then(|buffer| buffer.read(cx).file())
15662                .map(|file| (file.worktree_id(cx), file.clone()))
15663                .unzip();
15664
15665            (
15666                project.task_store().read(cx).task_inventory().cloned(),
15667                worktree_id,
15668                file,
15669            )
15670        });
15671
15672        let tags = mem::take(&mut runnable.tags);
15673        let language = runnable.language.clone();
15674        cx.spawn(async move |cx| {
15675            let mut templates_with_tags = Vec::new();
15676            if let Some(inventory) = inventory {
15677                for RunnableTag(tag) in tags {
15678                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15679                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15680                    }) else {
15681                        return templates_with_tags;
15682                    };
15683                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15684                        move |(_, template)| {
15685                            template.tags.iter().any(|source_tag| source_tag == &tag)
15686                        },
15687                    ));
15688                }
15689            }
15690            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15691
15692            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15693                // Strongest source wins; if we have worktree tag binding, prefer that to
15694                // global and language bindings;
15695                // if we have a global binding, prefer that to language binding.
15696                let first_mismatch = templates_with_tags
15697                    .iter()
15698                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15699                if let Some(index) = first_mismatch {
15700                    templates_with_tags.truncate(index);
15701                }
15702            }
15703
15704            templates_with_tags
15705        })
15706    }
15707
15708    pub fn move_to_enclosing_bracket(
15709        &mut self,
15710        _: &MoveToEnclosingBracket,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713    ) {
15714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15715        self.change_selections(Default::default(), window, cx, |s| {
15716            s.move_offsets_with(|snapshot, selection| {
15717                let Some(enclosing_bracket_ranges) =
15718                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15719                else {
15720                    return;
15721                };
15722
15723                let mut best_length = usize::MAX;
15724                let mut best_inside = false;
15725                let mut best_in_bracket_range = false;
15726                let mut best_destination = None;
15727                for (open, close) in enclosing_bracket_ranges {
15728                    let close = close.to_inclusive();
15729                    let length = close.end() - open.start;
15730                    let inside = selection.start >= open.end && selection.end <= *close.start();
15731                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15732                        || close.contains(&selection.head());
15733
15734                    // If best is next to a bracket and current isn't, skip
15735                    if !in_bracket_range && best_in_bracket_range {
15736                        continue;
15737                    }
15738
15739                    // Prefer smaller lengths unless best is inside and current isn't
15740                    if length > best_length && (best_inside || !inside) {
15741                        continue;
15742                    }
15743
15744                    best_length = length;
15745                    best_inside = inside;
15746                    best_in_bracket_range = in_bracket_range;
15747                    best_destination = Some(
15748                        if close.contains(&selection.start) && close.contains(&selection.end) {
15749                            if inside { open.end } else { open.start }
15750                        } else if inside {
15751                            *close.start()
15752                        } else {
15753                            *close.end()
15754                        },
15755                    );
15756                }
15757
15758                if let Some(destination) = best_destination {
15759                    selection.collapse_to(destination, SelectionGoal::None);
15760                }
15761            })
15762        });
15763    }
15764
15765    pub fn undo_selection(
15766        &mut self,
15767        _: &UndoSelection,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) {
15771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15772        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15773            self.selection_history.mode = SelectionHistoryMode::Undoing;
15774            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15775                this.end_selection(window, cx);
15776                this.change_selections(
15777                    SelectionEffects::scroll(Autoscroll::newest()),
15778                    window,
15779                    cx,
15780                    |s| s.select_anchors(entry.selections.to_vec()),
15781                );
15782            });
15783            self.selection_history.mode = SelectionHistoryMode::Normal;
15784
15785            self.select_next_state = entry.select_next_state;
15786            self.select_prev_state = entry.select_prev_state;
15787            self.add_selections_state = entry.add_selections_state;
15788        }
15789    }
15790
15791    pub fn redo_selection(
15792        &mut self,
15793        _: &RedoSelection,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15798        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15799            self.selection_history.mode = SelectionHistoryMode::Redoing;
15800            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15801                this.end_selection(window, cx);
15802                this.change_selections(
15803                    SelectionEffects::scroll(Autoscroll::newest()),
15804                    window,
15805                    cx,
15806                    |s| s.select_anchors(entry.selections.to_vec()),
15807                );
15808            });
15809            self.selection_history.mode = SelectionHistoryMode::Normal;
15810
15811            self.select_next_state = entry.select_next_state;
15812            self.select_prev_state = entry.select_prev_state;
15813            self.add_selections_state = entry.add_selections_state;
15814        }
15815    }
15816
15817    pub fn expand_excerpts(
15818        &mut self,
15819        action: &ExpandExcerpts,
15820        _: &mut Window,
15821        cx: &mut Context<Self>,
15822    ) {
15823        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15824    }
15825
15826    pub fn expand_excerpts_down(
15827        &mut self,
15828        action: &ExpandExcerptsDown,
15829        _: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15833    }
15834
15835    pub fn expand_excerpts_up(
15836        &mut self,
15837        action: &ExpandExcerptsUp,
15838        _: &mut Window,
15839        cx: &mut Context<Self>,
15840    ) {
15841        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15842    }
15843
15844    pub fn expand_excerpts_for_direction(
15845        &mut self,
15846        lines: u32,
15847        direction: ExpandExcerptDirection,
15848
15849        cx: &mut Context<Self>,
15850    ) {
15851        let selections = self.selections.disjoint_anchors_arc();
15852
15853        let lines = if lines == 0 {
15854            EditorSettings::get_global(cx).expand_excerpt_lines
15855        } else {
15856            lines
15857        };
15858
15859        self.buffer.update(cx, |buffer, cx| {
15860            let snapshot = buffer.snapshot(cx);
15861            let mut excerpt_ids = selections
15862                .iter()
15863                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15864                .collect::<Vec<_>>();
15865            excerpt_ids.sort();
15866            excerpt_ids.dedup();
15867            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15868        })
15869    }
15870
15871    pub fn expand_excerpt(
15872        &mut self,
15873        excerpt: ExcerptId,
15874        direction: ExpandExcerptDirection,
15875        window: &mut Window,
15876        cx: &mut Context<Self>,
15877    ) {
15878        let current_scroll_position = self.scroll_position(cx);
15879        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15880        let mut should_scroll_up = false;
15881
15882        if direction == ExpandExcerptDirection::Down {
15883            let multi_buffer = self.buffer.read(cx);
15884            let snapshot = multi_buffer.snapshot(cx);
15885            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15886                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15887                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15888            {
15889                let buffer_snapshot = buffer.read(cx).snapshot();
15890                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15891                let last_row = buffer_snapshot.max_point().row;
15892                let lines_below = last_row.saturating_sub(excerpt_end_row);
15893                should_scroll_up = lines_below >= lines_to_expand;
15894            }
15895        }
15896
15897        self.buffer.update(cx, |buffer, cx| {
15898            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15899        });
15900
15901        if should_scroll_up {
15902            let new_scroll_position =
15903                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15904            self.set_scroll_position(new_scroll_position, window, cx);
15905        }
15906    }
15907
15908    pub fn go_to_singleton_buffer_point(
15909        &mut self,
15910        point: Point,
15911        window: &mut Window,
15912        cx: &mut Context<Self>,
15913    ) {
15914        self.go_to_singleton_buffer_range(point..point, window, cx);
15915    }
15916
15917    pub fn go_to_singleton_buffer_range(
15918        &mut self,
15919        range: Range<Point>,
15920        window: &mut Window,
15921        cx: &mut Context<Self>,
15922    ) {
15923        let multibuffer = self.buffer().read(cx);
15924        let Some(buffer) = multibuffer.as_singleton() else {
15925            return;
15926        };
15927        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15928            return;
15929        };
15930        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15931            return;
15932        };
15933        self.change_selections(
15934            SelectionEffects::default().nav_history(true),
15935            window,
15936            cx,
15937            |s| s.select_anchor_ranges([start..end]),
15938        );
15939    }
15940
15941    pub fn go_to_diagnostic(
15942        &mut self,
15943        action: &GoToDiagnostic,
15944        window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) {
15947        if !self.diagnostics_enabled() {
15948            return;
15949        }
15950        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15951        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15952    }
15953
15954    pub fn go_to_prev_diagnostic(
15955        &mut self,
15956        action: &GoToPreviousDiagnostic,
15957        window: &mut Window,
15958        cx: &mut Context<Self>,
15959    ) {
15960        if !self.diagnostics_enabled() {
15961            return;
15962        }
15963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15964        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15965    }
15966
15967    pub fn go_to_diagnostic_impl(
15968        &mut self,
15969        direction: Direction,
15970        severity: GoToDiagnosticSeverityFilter,
15971        window: &mut Window,
15972        cx: &mut Context<Self>,
15973    ) {
15974        let buffer = self.buffer.read(cx).snapshot(cx);
15975        let selection = self.selections.newest::<usize>(cx);
15976
15977        let mut active_group_id = None;
15978        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15979            && active_group.active_range.start.to_offset(&buffer) == selection.start
15980        {
15981            active_group_id = Some(active_group.group_id);
15982        }
15983
15984        fn filtered<'a>(
15985            snapshot: EditorSnapshot,
15986            severity: GoToDiagnosticSeverityFilter,
15987            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
15988        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
15989            diagnostics
15990                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15991                .filter(|entry| entry.range.start != entry.range.end)
15992                .filter(|entry| !entry.diagnostic.is_unnecessary)
15993                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15994        }
15995
15996        let snapshot = self.snapshot(window, cx);
15997        let before = filtered(
15998            snapshot.clone(),
15999            severity,
16000            buffer
16001                .diagnostics_in_range(0..selection.start)
16002                .filter(|entry| entry.range.start <= selection.start),
16003        );
16004        let after = filtered(
16005            snapshot,
16006            severity,
16007            buffer
16008                .diagnostics_in_range(selection.start..buffer.len())
16009                .filter(|entry| entry.range.start >= selection.start),
16010        );
16011
16012        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16013        if direction == Direction::Prev {
16014            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16015            {
16016                for diagnostic in prev_diagnostics.into_iter().rev() {
16017                    if diagnostic.range.start != selection.start
16018                        || active_group_id
16019                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16020                    {
16021                        found = Some(diagnostic);
16022                        break 'outer;
16023                    }
16024                }
16025            }
16026        } else {
16027            for diagnostic in after.chain(before) {
16028                if diagnostic.range.start != selection.start
16029                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16030                {
16031                    found = Some(diagnostic);
16032                    break;
16033                }
16034            }
16035        }
16036        let Some(next_diagnostic) = found else {
16037            return;
16038        };
16039
16040        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16041        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16042            return;
16043        };
16044        self.change_selections(Default::default(), window, cx, |s| {
16045            s.select_ranges(vec![
16046                next_diagnostic.range.start..next_diagnostic.range.start,
16047            ])
16048        });
16049        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16050        self.refresh_edit_prediction(false, true, window, cx);
16051    }
16052
16053    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16055        let snapshot = self.snapshot(window, cx);
16056        let selection = self.selections.newest::<Point>(cx);
16057        self.go_to_hunk_before_or_after_position(
16058            &snapshot,
16059            selection.head(),
16060            Direction::Next,
16061            window,
16062            cx,
16063        );
16064    }
16065
16066    pub fn go_to_hunk_before_or_after_position(
16067        &mut self,
16068        snapshot: &EditorSnapshot,
16069        position: Point,
16070        direction: Direction,
16071        window: &mut Window,
16072        cx: &mut Context<Editor>,
16073    ) {
16074        let row = if direction == Direction::Next {
16075            self.hunk_after_position(snapshot, position)
16076                .map(|hunk| hunk.row_range.start)
16077        } else {
16078            self.hunk_before_position(snapshot, position)
16079        };
16080
16081        if let Some(row) = row {
16082            let destination = Point::new(row.0, 0);
16083            let autoscroll = Autoscroll::center();
16084
16085            self.unfold_ranges(&[destination..destination], false, false, cx);
16086            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16087                s.select_ranges([destination..destination]);
16088            });
16089        }
16090    }
16091
16092    fn hunk_after_position(
16093        &mut self,
16094        snapshot: &EditorSnapshot,
16095        position: Point,
16096    ) -> Option<MultiBufferDiffHunk> {
16097        snapshot
16098            .buffer_snapshot()
16099            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16100            .find(|hunk| hunk.row_range.start.0 > position.row)
16101            .or_else(|| {
16102                snapshot
16103                    .buffer_snapshot()
16104                    .diff_hunks_in_range(Point::zero()..position)
16105                    .find(|hunk| hunk.row_range.end.0 < position.row)
16106            })
16107    }
16108
16109    fn go_to_prev_hunk(
16110        &mut self,
16111        _: &GoToPreviousHunk,
16112        window: &mut Window,
16113        cx: &mut Context<Self>,
16114    ) {
16115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16116        let snapshot = self.snapshot(window, cx);
16117        let selection = self.selections.newest::<Point>(cx);
16118        self.go_to_hunk_before_or_after_position(
16119            &snapshot,
16120            selection.head(),
16121            Direction::Prev,
16122            window,
16123            cx,
16124        );
16125    }
16126
16127    fn hunk_before_position(
16128        &mut self,
16129        snapshot: &EditorSnapshot,
16130        position: Point,
16131    ) -> Option<MultiBufferRow> {
16132        snapshot
16133            .buffer_snapshot()
16134            .diff_hunk_before(position)
16135            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16136    }
16137
16138    fn go_to_next_change(
16139        &mut self,
16140        _: &GoToNextChange,
16141        window: &mut Window,
16142        cx: &mut Context<Self>,
16143    ) {
16144        if let Some(selections) = self
16145            .change_list
16146            .next_change(1, Direction::Next)
16147            .map(|s| s.to_vec())
16148        {
16149            self.change_selections(Default::default(), window, cx, |s| {
16150                let map = s.display_map();
16151                s.select_display_ranges(selections.iter().map(|a| {
16152                    let point = a.to_display_point(&map);
16153                    point..point
16154                }))
16155            })
16156        }
16157    }
16158
16159    fn go_to_previous_change(
16160        &mut self,
16161        _: &GoToPreviousChange,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) {
16165        if let Some(selections) = self
16166            .change_list
16167            .next_change(1, Direction::Prev)
16168            .map(|s| s.to_vec())
16169        {
16170            self.change_selections(Default::default(), window, cx, |s| {
16171                let map = s.display_map();
16172                s.select_display_ranges(selections.iter().map(|a| {
16173                    let point = a.to_display_point(&map);
16174                    point..point
16175                }))
16176            })
16177        }
16178    }
16179
16180    pub fn go_to_next_document_highlight(
16181        &mut self,
16182        _: &GoToNextDocumentHighlight,
16183        window: &mut Window,
16184        cx: &mut Context<Self>,
16185    ) {
16186        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16187    }
16188
16189    pub fn go_to_prev_document_highlight(
16190        &mut self,
16191        _: &GoToPreviousDocumentHighlight,
16192        window: &mut Window,
16193        cx: &mut Context<Self>,
16194    ) {
16195        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16196    }
16197
16198    pub fn go_to_document_highlight_before_or_after_position(
16199        &mut self,
16200        direction: Direction,
16201        window: &mut Window,
16202        cx: &mut Context<Editor>,
16203    ) {
16204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16205        let snapshot = self.snapshot(window, cx);
16206        let buffer = &snapshot.buffer_snapshot();
16207        let position = self.selections.newest::<Point>(cx).head();
16208        let anchor_position = buffer.anchor_after(position);
16209
16210        // Get all document highlights (both read and write)
16211        let mut all_highlights = Vec::new();
16212
16213        if let Some((_, read_highlights)) = self
16214            .background_highlights
16215            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16216        {
16217            all_highlights.extend(read_highlights.iter());
16218        }
16219
16220        if let Some((_, write_highlights)) = self
16221            .background_highlights
16222            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16223        {
16224            all_highlights.extend(write_highlights.iter());
16225        }
16226
16227        if all_highlights.is_empty() {
16228            return;
16229        }
16230
16231        // Sort highlights by position
16232        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16233
16234        let target_highlight = match direction {
16235            Direction::Next => {
16236                // Find the first highlight after the current position
16237                all_highlights
16238                    .iter()
16239                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16240            }
16241            Direction::Prev => {
16242                // Find the last highlight before the current position
16243                all_highlights
16244                    .iter()
16245                    .rev()
16246                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16247            }
16248        };
16249
16250        if let Some(highlight) = target_highlight {
16251            let destination = highlight.start.to_point(buffer);
16252            let autoscroll = Autoscroll::center();
16253
16254            self.unfold_ranges(&[destination..destination], false, false, cx);
16255            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16256                s.select_ranges([destination..destination]);
16257            });
16258        }
16259    }
16260
16261    fn go_to_line<T: 'static>(
16262        &mut self,
16263        position: Anchor,
16264        highlight_color: Option<Hsla>,
16265        window: &mut Window,
16266        cx: &mut Context<Self>,
16267    ) {
16268        let snapshot = self.snapshot(window, cx).display_snapshot;
16269        let position = position.to_point(&snapshot.buffer_snapshot());
16270        let start = snapshot
16271            .buffer_snapshot()
16272            .clip_point(Point::new(position.row, 0), Bias::Left);
16273        let end = start + Point::new(1, 0);
16274        let start = snapshot.buffer_snapshot().anchor_before(start);
16275        let end = snapshot.buffer_snapshot().anchor_before(end);
16276
16277        self.highlight_rows::<T>(
16278            start..end,
16279            highlight_color
16280                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16281            Default::default(),
16282            cx,
16283        );
16284
16285        if self.buffer.read(cx).is_singleton() {
16286            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16287        }
16288    }
16289
16290    pub fn go_to_definition(
16291        &mut self,
16292        _: &GoToDefinition,
16293        window: &mut Window,
16294        cx: &mut Context<Self>,
16295    ) -> Task<Result<Navigated>> {
16296        let definition =
16297            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16298        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16299        cx.spawn_in(window, async move |editor, cx| {
16300            if definition.await? == Navigated::Yes {
16301                return Ok(Navigated::Yes);
16302            }
16303            match fallback_strategy {
16304                GoToDefinitionFallback::None => Ok(Navigated::No),
16305                GoToDefinitionFallback::FindAllReferences => {
16306                    match editor.update_in(cx, |editor, window, cx| {
16307                        editor.find_all_references(&FindAllReferences, window, cx)
16308                    })? {
16309                        Some(references) => references.await,
16310                        None => Ok(Navigated::No),
16311                    }
16312                }
16313            }
16314        })
16315    }
16316
16317    pub fn go_to_declaration(
16318        &mut self,
16319        _: &GoToDeclaration,
16320        window: &mut Window,
16321        cx: &mut Context<Self>,
16322    ) -> Task<Result<Navigated>> {
16323        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16324    }
16325
16326    pub fn go_to_declaration_split(
16327        &mut self,
16328        _: &GoToDeclaration,
16329        window: &mut Window,
16330        cx: &mut Context<Self>,
16331    ) -> Task<Result<Navigated>> {
16332        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16333    }
16334
16335    pub fn go_to_implementation(
16336        &mut self,
16337        _: &GoToImplementation,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) -> Task<Result<Navigated>> {
16341        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16342    }
16343
16344    pub fn go_to_implementation_split(
16345        &mut self,
16346        _: &GoToImplementationSplit,
16347        window: &mut Window,
16348        cx: &mut Context<Self>,
16349    ) -> Task<Result<Navigated>> {
16350        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16351    }
16352
16353    pub fn go_to_type_definition(
16354        &mut self,
16355        _: &GoToTypeDefinition,
16356        window: &mut Window,
16357        cx: &mut Context<Self>,
16358    ) -> Task<Result<Navigated>> {
16359        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16360    }
16361
16362    pub fn go_to_definition_split(
16363        &mut self,
16364        _: &GoToDefinitionSplit,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) -> Task<Result<Navigated>> {
16368        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16369    }
16370
16371    pub fn go_to_type_definition_split(
16372        &mut self,
16373        _: &GoToTypeDefinitionSplit,
16374        window: &mut Window,
16375        cx: &mut Context<Self>,
16376    ) -> Task<Result<Navigated>> {
16377        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16378    }
16379
16380    fn go_to_definition_of_kind(
16381        &mut self,
16382        kind: GotoDefinitionKind,
16383        split: bool,
16384        window: &mut Window,
16385        cx: &mut Context<Self>,
16386    ) -> Task<Result<Navigated>> {
16387        let Some(provider) = self.semantics_provider.clone() else {
16388            return Task::ready(Ok(Navigated::No));
16389        };
16390        let head = self.selections.newest::<usize>(cx).head();
16391        let buffer = self.buffer.read(cx);
16392        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16393            return Task::ready(Ok(Navigated::No));
16394        };
16395        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16396            return Task::ready(Ok(Navigated::No));
16397        };
16398
16399        cx.spawn_in(window, async move |editor, cx| {
16400            let Some(definitions) = definitions.await? else {
16401                return Ok(Navigated::No);
16402            };
16403            let navigated = editor
16404                .update_in(cx, |editor, window, cx| {
16405                    editor.navigate_to_hover_links(
16406                        Some(kind),
16407                        definitions
16408                            .into_iter()
16409                            .filter(|location| {
16410                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16411                            })
16412                            .map(HoverLink::Text)
16413                            .collect::<Vec<_>>(),
16414                        split,
16415                        window,
16416                        cx,
16417                    )
16418                })?
16419                .await?;
16420            anyhow::Ok(navigated)
16421        })
16422    }
16423
16424    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16425        let selection = self.selections.newest_anchor();
16426        let head = selection.head();
16427        let tail = selection.tail();
16428
16429        let Some((buffer, start_position)) =
16430            self.buffer.read(cx).text_anchor_for_position(head, cx)
16431        else {
16432            return;
16433        };
16434
16435        let end_position = if head != tail {
16436            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16437                return;
16438            };
16439            Some(pos)
16440        } else {
16441            None
16442        };
16443
16444        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16445            let url = if let Some(end_pos) = end_position {
16446                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16447            } else {
16448                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16449            };
16450
16451            if let Some(url) = url {
16452                cx.update(|window, cx| {
16453                    if parse_zed_link(&url, cx).is_some() {
16454                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16455                    } else {
16456                        cx.open_url(&url);
16457                    }
16458                })?;
16459            }
16460
16461            anyhow::Ok(())
16462        });
16463
16464        url_finder.detach();
16465    }
16466
16467    pub fn open_selected_filename(
16468        &mut self,
16469        _: &OpenSelectedFilename,
16470        window: &mut Window,
16471        cx: &mut Context<Self>,
16472    ) {
16473        let Some(workspace) = self.workspace() else {
16474            return;
16475        };
16476
16477        let position = self.selections.newest_anchor().head();
16478
16479        let Some((buffer, buffer_position)) =
16480            self.buffer.read(cx).text_anchor_for_position(position, cx)
16481        else {
16482            return;
16483        };
16484
16485        let project = self.project.clone();
16486
16487        cx.spawn_in(window, async move |_, cx| {
16488            let result = find_file(&buffer, project, buffer_position, cx).await;
16489
16490            if let Some((_, path)) = result {
16491                workspace
16492                    .update_in(cx, |workspace, window, cx| {
16493                        workspace.open_resolved_path(path, window, cx)
16494                    })?
16495                    .await?;
16496            }
16497            anyhow::Ok(())
16498        })
16499        .detach();
16500    }
16501
16502    pub(crate) fn navigate_to_hover_links(
16503        &mut self,
16504        kind: Option<GotoDefinitionKind>,
16505        definitions: Vec<HoverLink>,
16506        split: bool,
16507        window: &mut Window,
16508        cx: &mut Context<Editor>,
16509    ) -> Task<Result<Navigated>> {
16510        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16511        let mut first_url_or_file = None;
16512        let definitions: Vec<_> = definitions
16513            .into_iter()
16514            .filter_map(|def| match def {
16515                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16516                HoverLink::InlayHint(lsp_location, server_id) => {
16517                    let computation =
16518                        self.compute_target_location(lsp_location, server_id, window, cx);
16519                    Some(cx.background_spawn(computation))
16520                }
16521                HoverLink::Url(url) => {
16522                    first_url_or_file = Some(Either::Left(url));
16523                    None
16524                }
16525                HoverLink::File(path) => {
16526                    first_url_or_file = Some(Either::Right(path));
16527                    None
16528                }
16529            })
16530            .collect();
16531
16532        let workspace = self.workspace();
16533
16534        cx.spawn_in(window, async move |editor, cx| {
16535            let locations: Vec<Location> = future::join_all(definitions)
16536                .await
16537                .into_iter()
16538                .filter_map(|location| location.transpose())
16539                .collect::<Result<_>>()
16540                .context("location tasks")?;
16541            let mut locations = cx.update(|_, cx| {
16542                locations
16543                    .into_iter()
16544                    .map(|location| {
16545                        let buffer = location.buffer.read(cx);
16546                        (location.buffer, location.range.to_point(buffer))
16547                    })
16548                    .into_group_map()
16549            })?;
16550            let mut num_locations = 0;
16551            for ranges in locations.values_mut() {
16552                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16553                ranges.dedup();
16554                num_locations += ranges.len();
16555            }
16556
16557            if num_locations > 1 {
16558                let Some(workspace) = workspace else {
16559                    return Ok(Navigated::No);
16560                };
16561
16562                let tab_kind = match kind {
16563                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16564                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16565                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16566                    Some(GotoDefinitionKind::Type) => "Types",
16567                };
16568                let title = editor
16569                    .update_in(cx, |_, _, cx| {
16570                        let target = locations
16571                            .iter()
16572                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16573                            .map(|(buffer, location)| {
16574                                buffer
16575                                    .read(cx)
16576                                    .text_for_range(location.clone())
16577                                    .collect::<String>()
16578                            })
16579                            .filter(|text| !text.contains('\n'))
16580                            .unique()
16581                            .take(3)
16582                            .join(", ");
16583                        if target.is_empty() {
16584                            tab_kind.to_owned()
16585                        } else {
16586                            format!("{tab_kind} for {target}")
16587                        }
16588                    })
16589                    .context("buffer title")?;
16590
16591                let opened = workspace
16592                    .update_in(cx, |workspace, window, cx| {
16593                        Self::open_locations_in_multibuffer(
16594                            workspace,
16595                            locations,
16596                            title,
16597                            split,
16598                            MultibufferSelectionMode::First,
16599                            window,
16600                            cx,
16601                        )
16602                    })
16603                    .is_ok();
16604
16605                anyhow::Ok(Navigated::from_bool(opened))
16606            } else if num_locations == 0 {
16607                // If there is one url or file, open it directly
16608                match first_url_or_file {
16609                    Some(Either::Left(url)) => {
16610                        cx.update(|_, cx| cx.open_url(&url))?;
16611                        Ok(Navigated::Yes)
16612                    }
16613                    Some(Either::Right(path)) => {
16614                        let Some(workspace) = workspace else {
16615                            return Ok(Navigated::No);
16616                        };
16617
16618                        workspace
16619                            .update_in(cx, |workspace, window, cx| {
16620                                workspace.open_resolved_path(path, window, cx)
16621                            })?
16622                            .await?;
16623                        Ok(Navigated::Yes)
16624                    }
16625                    None => Ok(Navigated::No),
16626                }
16627            } else {
16628                let Some(workspace) = workspace else {
16629                    return Ok(Navigated::No);
16630                };
16631
16632                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16633                let target_range = target_ranges.first().unwrap().clone();
16634
16635                editor.update_in(cx, |editor, window, cx| {
16636                    let range = target_range.to_point(target_buffer.read(cx));
16637                    let range = editor.range_for_match(&range);
16638                    let range = collapse_multiline_range(range);
16639
16640                    if !split
16641                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16642                    {
16643                        editor.go_to_singleton_buffer_range(range, window, cx);
16644                    } else {
16645                        let pane = workspace.read(cx).active_pane().clone();
16646                        window.defer(cx, move |window, cx| {
16647                            let target_editor: Entity<Self> =
16648                                workspace.update(cx, |workspace, cx| {
16649                                    let pane = if split {
16650                                        workspace.adjacent_pane(window, cx)
16651                                    } else {
16652                                        workspace.active_pane().clone()
16653                                    };
16654
16655                                    workspace.open_project_item(
16656                                        pane,
16657                                        target_buffer.clone(),
16658                                        true,
16659                                        true,
16660                                        window,
16661                                        cx,
16662                                    )
16663                                });
16664                            target_editor.update(cx, |target_editor, cx| {
16665                                // When selecting a definition in a different buffer, disable the nav history
16666                                // to avoid creating a history entry at the previous cursor location.
16667                                pane.update(cx, |pane, _| pane.disable_history());
16668                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16669                                pane.update(cx, |pane, _| pane.enable_history());
16670                            });
16671                        });
16672                    }
16673                    Navigated::Yes
16674                })
16675            }
16676        })
16677    }
16678
16679    fn compute_target_location(
16680        &self,
16681        lsp_location: lsp::Location,
16682        server_id: LanguageServerId,
16683        window: &mut Window,
16684        cx: &mut Context<Self>,
16685    ) -> Task<anyhow::Result<Option<Location>>> {
16686        let Some(project) = self.project.clone() else {
16687            return Task::ready(Ok(None));
16688        };
16689
16690        cx.spawn_in(window, async move |editor, cx| {
16691            let location_task = editor.update(cx, |_, cx| {
16692                project.update(cx, |project, cx| {
16693                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16694                })
16695            })?;
16696            let location = Some({
16697                let target_buffer_handle = location_task.await.context("open local buffer")?;
16698                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16699                    let target_start = target_buffer
16700                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16701                    let target_end = target_buffer
16702                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16703                    target_buffer.anchor_after(target_start)
16704                        ..target_buffer.anchor_before(target_end)
16705                })?;
16706                Location {
16707                    buffer: target_buffer_handle,
16708                    range,
16709                }
16710            });
16711            Ok(location)
16712        })
16713    }
16714
16715    pub fn find_all_references(
16716        &mut self,
16717        _: &FindAllReferences,
16718        window: &mut Window,
16719        cx: &mut Context<Self>,
16720    ) -> Option<Task<Result<Navigated>>> {
16721        let selection = self.selections.newest::<usize>(cx);
16722        let multi_buffer = self.buffer.read(cx);
16723        let head = selection.head();
16724
16725        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16726        let head_anchor = multi_buffer_snapshot.anchor_at(
16727            head,
16728            if head < selection.tail() {
16729                Bias::Right
16730            } else {
16731                Bias::Left
16732            },
16733        );
16734
16735        match self
16736            .find_all_references_task_sources
16737            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16738        {
16739            Ok(_) => {
16740                log::info!(
16741                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16742                );
16743                return None;
16744            }
16745            Err(i) => {
16746                self.find_all_references_task_sources.insert(i, head_anchor);
16747            }
16748        }
16749
16750        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16751        let workspace = self.workspace()?;
16752        let project = workspace.read(cx).project().clone();
16753        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16754        Some(cx.spawn_in(window, async move |editor, cx| {
16755            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16756                if let Ok(i) = editor
16757                    .find_all_references_task_sources
16758                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16759                {
16760                    editor.find_all_references_task_sources.remove(i);
16761                }
16762            });
16763
16764            let Some(locations) = references.await? else {
16765                return anyhow::Ok(Navigated::No);
16766            };
16767            let mut locations = cx.update(|_, cx| {
16768                locations
16769                    .into_iter()
16770                    .map(|location| {
16771                        let buffer = location.buffer.read(cx);
16772                        (location.buffer, location.range.to_point(buffer))
16773                    })
16774                    .into_group_map()
16775            })?;
16776            if locations.is_empty() {
16777                return anyhow::Ok(Navigated::No);
16778            }
16779            for ranges in locations.values_mut() {
16780                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16781                ranges.dedup();
16782            }
16783
16784            workspace.update_in(cx, |workspace, window, cx| {
16785                let target = locations
16786                    .iter()
16787                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16788                    .map(|(buffer, location)| {
16789                        buffer
16790                            .read(cx)
16791                            .text_for_range(location.clone())
16792                            .collect::<String>()
16793                    })
16794                    .filter(|text| !text.contains('\n'))
16795                    .unique()
16796                    .take(3)
16797                    .join(", ");
16798                let title = if target.is_empty() {
16799                    "References".to_owned()
16800                } else {
16801                    format!("References to {target}")
16802                };
16803                Self::open_locations_in_multibuffer(
16804                    workspace,
16805                    locations,
16806                    title,
16807                    false,
16808                    MultibufferSelectionMode::First,
16809                    window,
16810                    cx,
16811                );
16812                Navigated::Yes
16813            })
16814        }))
16815    }
16816
16817    /// Opens a multibuffer with the given project locations in it
16818    pub fn open_locations_in_multibuffer(
16819        workspace: &mut Workspace,
16820        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16821        title: String,
16822        split: bool,
16823        multibuffer_selection_mode: MultibufferSelectionMode,
16824        window: &mut Window,
16825        cx: &mut Context<Workspace>,
16826    ) {
16827        if locations.is_empty() {
16828            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16829            return;
16830        }
16831
16832        let capability = workspace.project().read(cx).capability();
16833        let mut ranges = <Vec<Range<Anchor>>>::new();
16834
16835        // a key to find existing multibuffer editors with the same set of locations
16836        // to prevent us from opening more and more multibuffer tabs for searches and the like
16837        let mut key = (title.clone(), vec![]);
16838        let excerpt_buffer = cx.new(|cx| {
16839            let key = &mut key.1;
16840            let mut multibuffer = MultiBuffer::new(capability);
16841            for (buffer, mut ranges_for_buffer) in locations {
16842                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16843                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16844                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16845                    PathKey::for_buffer(&buffer, cx),
16846                    buffer.clone(),
16847                    ranges_for_buffer,
16848                    multibuffer_context_lines(cx),
16849                    cx,
16850                );
16851                ranges.extend(new_ranges)
16852            }
16853
16854            multibuffer.with_title(title)
16855        });
16856        let existing = workspace.active_pane().update(cx, |pane, cx| {
16857            pane.items()
16858                .filter_map(|item| item.downcast::<Editor>())
16859                .find(|editor| {
16860                    editor
16861                        .read(cx)
16862                        .lookup_key
16863                        .as_ref()
16864                        .and_then(|it| {
16865                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16866                        })
16867                        .is_some_and(|it| *it == key)
16868                })
16869        });
16870        let editor = existing.unwrap_or_else(|| {
16871            cx.new(|cx| {
16872                let mut editor = Editor::for_multibuffer(
16873                    excerpt_buffer,
16874                    Some(workspace.project().clone()),
16875                    window,
16876                    cx,
16877                );
16878                editor.lookup_key = Some(Box::new(key));
16879                editor
16880            })
16881        });
16882        editor.update(cx, |editor, cx| {
16883            match multibuffer_selection_mode {
16884                MultibufferSelectionMode::First => {
16885                    if let Some(first_range) = ranges.first() {
16886                        editor.change_selections(
16887                            SelectionEffects::no_scroll(),
16888                            window,
16889                            cx,
16890                            |selections| {
16891                                selections.clear_disjoint();
16892                                selections
16893                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16894                            },
16895                        );
16896                    }
16897                    editor.highlight_background::<Self>(
16898                        &ranges,
16899                        |theme| theme.colors().editor_highlighted_line_background,
16900                        cx,
16901                    );
16902                }
16903                MultibufferSelectionMode::All => {
16904                    editor.change_selections(
16905                        SelectionEffects::no_scroll(),
16906                        window,
16907                        cx,
16908                        |selections| {
16909                            selections.clear_disjoint();
16910                            selections.select_anchor_ranges(ranges);
16911                        },
16912                    );
16913                }
16914            }
16915            editor.register_buffers_with_language_servers(cx);
16916        });
16917
16918        let item = Box::new(editor);
16919        let item_id = item.item_id();
16920
16921        if split {
16922            let pane = workspace.adjacent_pane(window, cx);
16923            workspace.add_item(pane, item, None, true, true, window, cx);
16924        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16925            let (preview_item_id, preview_item_idx) =
16926                workspace.active_pane().read_with(cx, |pane, _| {
16927                    (pane.preview_item_id(), pane.preview_item_idx())
16928                });
16929
16930            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16931
16932            if let Some(preview_item_id) = preview_item_id {
16933                workspace.active_pane().update(cx, |pane, cx| {
16934                    pane.remove_item(preview_item_id, false, false, window, cx);
16935                });
16936            }
16937        } else {
16938            workspace.add_item_to_active_pane(item, None, true, window, cx);
16939        }
16940        workspace.active_pane().update(cx, |pane, cx| {
16941            pane.set_preview_item_id(Some(item_id), cx);
16942        });
16943    }
16944
16945    pub fn rename(
16946        &mut self,
16947        _: &Rename,
16948        window: &mut Window,
16949        cx: &mut Context<Self>,
16950    ) -> Option<Task<Result<()>>> {
16951        use language::ToOffset as _;
16952
16953        let provider = self.semantics_provider.clone()?;
16954        let selection = self.selections.newest_anchor().clone();
16955        let (cursor_buffer, cursor_buffer_position) = self
16956            .buffer
16957            .read(cx)
16958            .text_anchor_for_position(selection.head(), cx)?;
16959        let (tail_buffer, cursor_buffer_position_end) = self
16960            .buffer
16961            .read(cx)
16962            .text_anchor_for_position(selection.tail(), cx)?;
16963        if tail_buffer != cursor_buffer {
16964            return None;
16965        }
16966
16967        let snapshot = cursor_buffer.read(cx).snapshot();
16968        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16969        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16970        let prepare_rename = provider
16971            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16972            .unwrap_or_else(|| Task::ready(Ok(None)));
16973        drop(snapshot);
16974
16975        Some(cx.spawn_in(window, async move |this, cx| {
16976            let rename_range = if let Some(range) = prepare_rename.await? {
16977                Some(range)
16978            } else {
16979                this.update(cx, |this, cx| {
16980                    let buffer = this.buffer.read(cx).snapshot(cx);
16981                    let mut buffer_highlights = this
16982                        .document_highlights_for_position(selection.head(), &buffer)
16983                        .filter(|highlight| {
16984                            highlight.start.excerpt_id == selection.head().excerpt_id
16985                                && highlight.end.excerpt_id == selection.head().excerpt_id
16986                        });
16987                    buffer_highlights
16988                        .next()
16989                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16990                })?
16991            };
16992            if let Some(rename_range) = rename_range {
16993                this.update_in(cx, |this, window, cx| {
16994                    let snapshot = cursor_buffer.read(cx).snapshot();
16995                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16996                    let cursor_offset_in_rename_range =
16997                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16998                    let cursor_offset_in_rename_range_end =
16999                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17000
17001                    this.take_rename(false, window, cx);
17002                    let buffer = this.buffer.read(cx).read(cx);
17003                    let cursor_offset = selection.head().to_offset(&buffer);
17004                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17005                    let rename_end = rename_start + rename_buffer_range.len();
17006                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17007                    let mut old_highlight_id = None;
17008                    let old_name: Arc<str> = buffer
17009                        .chunks(rename_start..rename_end, true)
17010                        .map(|chunk| {
17011                            if old_highlight_id.is_none() {
17012                                old_highlight_id = chunk.syntax_highlight_id;
17013                            }
17014                            chunk.text
17015                        })
17016                        .collect::<String>()
17017                        .into();
17018
17019                    drop(buffer);
17020
17021                    // Position the selection in the rename editor so that it matches the current selection.
17022                    this.show_local_selections = false;
17023                    let rename_editor = cx.new(|cx| {
17024                        let mut editor = Editor::single_line(window, cx);
17025                        editor.buffer.update(cx, |buffer, cx| {
17026                            buffer.edit([(0..0, old_name.clone())], None, cx)
17027                        });
17028                        let rename_selection_range = match cursor_offset_in_rename_range
17029                            .cmp(&cursor_offset_in_rename_range_end)
17030                        {
17031                            Ordering::Equal => {
17032                                editor.select_all(&SelectAll, window, cx);
17033                                return editor;
17034                            }
17035                            Ordering::Less => {
17036                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17037                            }
17038                            Ordering::Greater => {
17039                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17040                            }
17041                        };
17042                        if rename_selection_range.end > old_name.len() {
17043                            editor.select_all(&SelectAll, window, cx);
17044                        } else {
17045                            editor.change_selections(Default::default(), window, cx, |s| {
17046                                s.select_ranges([rename_selection_range]);
17047                            });
17048                        }
17049                        editor
17050                    });
17051                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17052                        if e == &EditorEvent::Focused {
17053                            cx.emit(EditorEvent::FocusedIn)
17054                        }
17055                    })
17056                    .detach();
17057
17058                    let write_highlights =
17059                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17060                    let read_highlights =
17061                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17062                    let ranges = write_highlights
17063                        .iter()
17064                        .flat_map(|(_, ranges)| ranges.iter())
17065                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17066                        .cloned()
17067                        .collect();
17068
17069                    this.highlight_text::<Rename>(
17070                        ranges,
17071                        HighlightStyle {
17072                            fade_out: Some(0.6),
17073                            ..Default::default()
17074                        },
17075                        cx,
17076                    );
17077                    let rename_focus_handle = rename_editor.focus_handle(cx);
17078                    window.focus(&rename_focus_handle);
17079                    let block_id = this.insert_blocks(
17080                        [BlockProperties {
17081                            style: BlockStyle::Flex,
17082                            placement: BlockPlacement::Below(range.start),
17083                            height: Some(1),
17084                            render: Arc::new({
17085                                let rename_editor = rename_editor.clone();
17086                                move |cx: &mut BlockContext| {
17087                                    let mut text_style = cx.editor_style.text.clone();
17088                                    if let Some(highlight_style) = old_highlight_id
17089                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17090                                    {
17091                                        text_style = text_style.highlight(highlight_style);
17092                                    }
17093                                    div()
17094                                        .block_mouse_except_scroll()
17095                                        .pl(cx.anchor_x)
17096                                        .child(EditorElement::new(
17097                                            &rename_editor,
17098                                            EditorStyle {
17099                                                background: cx.theme().system().transparent,
17100                                                local_player: cx.editor_style.local_player,
17101                                                text: text_style,
17102                                                scrollbar_width: cx.editor_style.scrollbar_width,
17103                                                syntax: cx.editor_style.syntax.clone(),
17104                                                status: cx.editor_style.status.clone(),
17105                                                inlay_hints_style: HighlightStyle {
17106                                                    font_weight: Some(FontWeight::BOLD),
17107                                                    ..make_inlay_hints_style(cx.app)
17108                                                },
17109                                                edit_prediction_styles: make_suggestion_styles(
17110                                                    cx.app,
17111                                                ),
17112                                                ..EditorStyle::default()
17113                                            },
17114                                        ))
17115                                        .into_any_element()
17116                                }
17117                            }),
17118                            priority: 0,
17119                        }],
17120                        Some(Autoscroll::fit()),
17121                        cx,
17122                    )[0];
17123                    this.pending_rename = Some(RenameState {
17124                        range,
17125                        old_name,
17126                        editor: rename_editor,
17127                        block_id,
17128                    });
17129                })?;
17130            }
17131
17132            Ok(())
17133        }))
17134    }
17135
17136    pub fn confirm_rename(
17137        &mut self,
17138        _: &ConfirmRename,
17139        window: &mut Window,
17140        cx: &mut Context<Self>,
17141    ) -> Option<Task<Result<()>>> {
17142        let rename = self.take_rename(false, window, cx)?;
17143        let workspace = self.workspace()?.downgrade();
17144        let (buffer, start) = self
17145            .buffer
17146            .read(cx)
17147            .text_anchor_for_position(rename.range.start, cx)?;
17148        let (end_buffer, _) = self
17149            .buffer
17150            .read(cx)
17151            .text_anchor_for_position(rename.range.end, cx)?;
17152        if buffer != end_buffer {
17153            return None;
17154        }
17155
17156        let old_name = rename.old_name;
17157        let new_name = rename.editor.read(cx).text(cx);
17158
17159        let rename = self.semantics_provider.as_ref()?.perform_rename(
17160            &buffer,
17161            start,
17162            new_name.clone(),
17163            cx,
17164        )?;
17165
17166        Some(cx.spawn_in(window, async move |editor, cx| {
17167            let project_transaction = rename.await?;
17168            Self::open_project_transaction(
17169                &editor,
17170                workspace,
17171                project_transaction,
17172                format!("Rename: {}{}", old_name, new_name),
17173                cx,
17174            )
17175            .await?;
17176
17177            editor.update(cx, |editor, cx| {
17178                editor.refresh_document_highlights(cx);
17179            })?;
17180            Ok(())
17181        }))
17182    }
17183
17184    fn take_rename(
17185        &mut self,
17186        moving_cursor: bool,
17187        window: &mut Window,
17188        cx: &mut Context<Self>,
17189    ) -> Option<RenameState> {
17190        let rename = self.pending_rename.take()?;
17191        if rename.editor.focus_handle(cx).is_focused(window) {
17192            window.focus(&self.focus_handle);
17193        }
17194
17195        self.remove_blocks(
17196            [rename.block_id].into_iter().collect(),
17197            Some(Autoscroll::fit()),
17198            cx,
17199        );
17200        self.clear_highlights::<Rename>(cx);
17201        self.show_local_selections = true;
17202
17203        if moving_cursor {
17204            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17205                editor.selections.newest::<usize>(cx).head()
17206            });
17207
17208            // Update the selection to match the position of the selection inside
17209            // the rename editor.
17210            let snapshot = self.buffer.read(cx).read(cx);
17211            let rename_range = rename.range.to_offset(&snapshot);
17212            let cursor_in_editor = snapshot
17213                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17214                .min(rename_range.end);
17215            drop(snapshot);
17216
17217            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17218                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17219            });
17220        } else {
17221            self.refresh_document_highlights(cx);
17222        }
17223
17224        Some(rename)
17225    }
17226
17227    pub fn pending_rename(&self) -> Option<&RenameState> {
17228        self.pending_rename.as_ref()
17229    }
17230
17231    fn format(
17232        &mut self,
17233        _: &Format,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) -> Option<Task<Result<()>>> {
17237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17238
17239        let project = match &self.project {
17240            Some(project) => project.clone(),
17241            None => return None,
17242        };
17243
17244        Some(self.perform_format(
17245            project,
17246            FormatTrigger::Manual,
17247            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17248            window,
17249            cx,
17250        ))
17251    }
17252
17253    fn format_selections(
17254        &mut self,
17255        _: &FormatSelections,
17256        window: &mut Window,
17257        cx: &mut Context<Self>,
17258    ) -> Option<Task<Result<()>>> {
17259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17260
17261        let project = match &self.project {
17262            Some(project) => project.clone(),
17263            None => return None,
17264        };
17265
17266        let ranges = self
17267            .selections
17268            .all_adjusted(cx)
17269            .into_iter()
17270            .map(|selection| selection.range())
17271            .collect_vec();
17272
17273        Some(self.perform_format(
17274            project,
17275            FormatTrigger::Manual,
17276            FormatTarget::Ranges(ranges),
17277            window,
17278            cx,
17279        ))
17280    }
17281
17282    fn perform_format(
17283        &mut self,
17284        project: Entity<Project>,
17285        trigger: FormatTrigger,
17286        target: FormatTarget,
17287        window: &mut Window,
17288        cx: &mut Context<Self>,
17289    ) -> Task<Result<()>> {
17290        let buffer = self.buffer.clone();
17291        let (buffers, target) = match target {
17292            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17293            FormatTarget::Ranges(selection_ranges) => {
17294                let multi_buffer = buffer.read(cx);
17295                let snapshot = multi_buffer.read(cx);
17296                let mut buffers = HashSet::default();
17297                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17298                    BTreeMap::new();
17299                for selection_range in selection_ranges {
17300                    for (buffer, buffer_range, _) in
17301                        snapshot.range_to_buffer_ranges(selection_range)
17302                    {
17303                        let buffer_id = buffer.remote_id();
17304                        let start = buffer.anchor_before(buffer_range.start);
17305                        let end = buffer.anchor_after(buffer_range.end);
17306                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17307                        buffer_id_to_ranges
17308                            .entry(buffer_id)
17309                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17310                            .or_insert_with(|| vec![start..end]);
17311                    }
17312                }
17313                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17314            }
17315        };
17316
17317        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17318        let selections_prev = transaction_id_prev
17319            .and_then(|transaction_id_prev| {
17320                // default to selections as they were after the last edit, if we have them,
17321                // instead of how they are now.
17322                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17323                // will take you back to where you made the last edit, instead of staying where you scrolled
17324                self.selection_history
17325                    .transaction(transaction_id_prev)
17326                    .map(|t| t.0.clone())
17327            })
17328            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17329
17330        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17331        let format = project.update(cx, |project, cx| {
17332            project.format(buffers, target, true, trigger, cx)
17333        });
17334
17335        cx.spawn_in(window, async move |editor, cx| {
17336            let transaction = futures::select_biased! {
17337                transaction = format.log_err().fuse() => transaction,
17338                () = timeout => {
17339                    log::warn!("timed out waiting for formatting");
17340                    None
17341                }
17342            };
17343
17344            buffer
17345                .update(cx, |buffer, cx| {
17346                    if let Some(transaction) = transaction
17347                        && !buffer.is_singleton()
17348                    {
17349                        buffer.push_transaction(&transaction.0, cx);
17350                    }
17351                    cx.notify();
17352                })
17353                .ok();
17354
17355            if let Some(transaction_id_now) =
17356                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17357            {
17358                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17359                if has_new_transaction {
17360                    _ = editor.update(cx, |editor, _| {
17361                        editor
17362                            .selection_history
17363                            .insert_transaction(transaction_id_now, selections_prev);
17364                    });
17365                }
17366            }
17367
17368            Ok(())
17369        })
17370    }
17371
17372    fn organize_imports(
17373        &mut self,
17374        _: &OrganizeImports,
17375        window: &mut Window,
17376        cx: &mut Context<Self>,
17377    ) -> Option<Task<Result<()>>> {
17378        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17379        let project = match &self.project {
17380            Some(project) => project.clone(),
17381            None => return None,
17382        };
17383        Some(self.perform_code_action_kind(
17384            project,
17385            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17386            window,
17387            cx,
17388        ))
17389    }
17390
17391    fn perform_code_action_kind(
17392        &mut self,
17393        project: Entity<Project>,
17394        kind: CodeActionKind,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) -> Task<Result<()>> {
17398        let buffer = self.buffer.clone();
17399        let buffers = buffer.read(cx).all_buffers();
17400        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17401        let apply_action = project.update(cx, |project, cx| {
17402            project.apply_code_action_kind(buffers, kind, true, cx)
17403        });
17404        cx.spawn_in(window, async move |_, cx| {
17405            let transaction = futures::select_biased! {
17406                () = timeout => {
17407                    log::warn!("timed out waiting for executing code action");
17408                    None
17409                }
17410                transaction = apply_action.log_err().fuse() => transaction,
17411            };
17412            buffer
17413                .update(cx, |buffer, cx| {
17414                    // check if we need this
17415                    if let Some(transaction) = transaction
17416                        && !buffer.is_singleton()
17417                    {
17418                        buffer.push_transaction(&transaction.0, cx);
17419                    }
17420                    cx.notify();
17421                })
17422                .ok();
17423            Ok(())
17424        })
17425    }
17426
17427    pub fn restart_language_server(
17428        &mut self,
17429        _: &RestartLanguageServer,
17430        _: &mut Window,
17431        cx: &mut Context<Self>,
17432    ) {
17433        if let Some(project) = self.project.clone() {
17434            self.buffer.update(cx, |multi_buffer, cx| {
17435                project.update(cx, |project, cx| {
17436                    project.restart_language_servers_for_buffers(
17437                        multi_buffer.all_buffers().into_iter().collect(),
17438                        HashSet::default(),
17439                        cx,
17440                    );
17441                });
17442            })
17443        }
17444    }
17445
17446    pub fn stop_language_server(
17447        &mut self,
17448        _: &StopLanguageServer,
17449        _: &mut Window,
17450        cx: &mut Context<Self>,
17451    ) {
17452        if let Some(project) = self.project.clone() {
17453            self.buffer.update(cx, |multi_buffer, cx| {
17454                project.update(cx, |project, cx| {
17455                    project.stop_language_servers_for_buffers(
17456                        multi_buffer.all_buffers().into_iter().collect(),
17457                        HashSet::default(),
17458                        cx,
17459                    );
17460                    cx.emit(project::Event::RefreshInlayHints);
17461                });
17462            });
17463        }
17464    }
17465
17466    fn cancel_language_server_work(
17467        workspace: &mut Workspace,
17468        _: &actions::CancelLanguageServerWork,
17469        _: &mut Window,
17470        cx: &mut Context<Workspace>,
17471    ) {
17472        let project = workspace.project();
17473        let buffers = workspace
17474            .active_item(cx)
17475            .and_then(|item| item.act_as::<Editor>(cx))
17476            .map_or(HashSet::default(), |editor| {
17477                editor.read(cx).buffer.read(cx).all_buffers()
17478            });
17479        project.update(cx, |project, cx| {
17480            project.cancel_language_server_work_for_buffers(buffers, cx);
17481        });
17482    }
17483
17484    fn show_character_palette(
17485        &mut self,
17486        _: &ShowCharacterPalette,
17487        window: &mut Window,
17488        _: &mut Context<Self>,
17489    ) {
17490        window.show_character_palette();
17491    }
17492
17493    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17494        if !self.diagnostics_enabled() {
17495            return;
17496        }
17497
17498        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17499            let buffer = self.buffer.read(cx).snapshot(cx);
17500            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17501            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17502            let is_valid = buffer
17503                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17504                .any(|entry| {
17505                    entry.diagnostic.is_primary
17506                        && !entry.range.is_empty()
17507                        && entry.range.start == primary_range_start
17508                        && entry.diagnostic.message == active_diagnostics.active_message
17509                });
17510
17511            if !is_valid {
17512                self.dismiss_diagnostics(cx);
17513            }
17514        }
17515    }
17516
17517    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17518        match &self.active_diagnostics {
17519            ActiveDiagnostic::Group(group) => Some(group),
17520            _ => None,
17521        }
17522    }
17523
17524    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17525        if !self.diagnostics_enabled() {
17526            return;
17527        }
17528        self.dismiss_diagnostics(cx);
17529        self.active_diagnostics = ActiveDiagnostic::All;
17530    }
17531
17532    fn activate_diagnostics(
17533        &mut self,
17534        buffer_id: BufferId,
17535        diagnostic: DiagnosticEntryRef<'_, usize>,
17536        window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) {
17539        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17540            return;
17541        }
17542        self.dismiss_diagnostics(cx);
17543        let snapshot = self.snapshot(window, cx);
17544        let buffer = self.buffer.read(cx).snapshot(cx);
17545        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17546            return;
17547        };
17548
17549        let diagnostic_group = buffer
17550            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17551            .collect::<Vec<_>>();
17552
17553        let blocks =
17554            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17555
17556        let blocks = self.display_map.update(cx, |display_map, cx| {
17557            display_map.insert_blocks(blocks, cx).into_iter().collect()
17558        });
17559        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17560            active_range: buffer.anchor_before(diagnostic.range.start)
17561                ..buffer.anchor_after(diagnostic.range.end),
17562            active_message: diagnostic.diagnostic.message.clone(),
17563            group_id: diagnostic.diagnostic.group_id,
17564            blocks,
17565        });
17566        cx.notify();
17567    }
17568
17569    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17570        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17571            return;
17572        };
17573
17574        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17575        if let ActiveDiagnostic::Group(group) = prev {
17576            self.display_map.update(cx, |display_map, cx| {
17577                display_map.remove_blocks(group.blocks, cx);
17578            });
17579            cx.notify();
17580        }
17581    }
17582
17583    /// Disable inline diagnostics rendering for this editor.
17584    pub fn disable_inline_diagnostics(&mut self) {
17585        self.inline_diagnostics_enabled = false;
17586        self.inline_diagnostics_update = Task::ready(());
17587        self.inline_diagnostics.clear();
17588    }
17589
17590    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17591        self.diagnostics_enabled = false;
17592        self.dismiss_diagnostics(cx);
17593        self.inline_diagnostics_update = Task::ready(());
17594        self.inline_diagnostics.clear();
17595    }
17596
17597    pub fn disable_word_completions(&mut self) {
17598        self.word_completions_enabled = false;
17599    }
17600
17601    pub fn diagnostics_enabled(&self) -> bool {
17602        self.diagnostics_enabled && self.mode.is_full()
17603    }
17604
17605    pub fn inline_diagnostics_enabled(&self) -> bool {
17606        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17607    }
17608
17609    pub fn show_inline_diagnostics(&self) -> bool {
17610        self.show_inline_diagnostics
17611    }
17612
17613    pub fn toggle_inline_diagnostics(
17614        &mut self,
17615        _: &ToggleInlineDiagnostics,
17616        window: &mut Window,
17617        cx: &mut Context<Editor>,
17618    ) {
17619        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17620        self.refresh_inline_diagnostics(false, window, cx);
17621    }
17622
17623    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17624        self.diagnostics_max_severity = severity;
17625        self.display_map.update(cx, |display_map, _| {
17626            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17627        });
17628    }
17629
17630    pub fn toggle_diagnostics(
17631        &mut self,
17632        _: &ToggleDiagnostics,
17633        window: &mut Window,
17634        cx: &mut Context<Editor>,
17635    ) {
17636        if !self.diagnostics_enabled() {
17637            return;
17638        }
17639
17640        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17641            EditorSettings::get_global(cx)
17642                .diagnostics_max_severity
17643                .filter(|severity| severity != &DiagnosticSeverity::Off)
17644                .unwrap_or(DiagnosticSeverity::Hint)
17645        } else {
17646            DiagnosticSeverity::Off
17647        };
17648        self.set_max_diagnostics_severity(new_severity, cx);
17649        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17650            self.active_diagnostics = ActiveDiagnostic::None;
17651            self.inline_diagnostics_update = Task::ready(());
17652            self.inline_diagnostics.clear();
17653        } else {
17654            self.refresh_inline_diagnostics(false, window, cx);
17655        }
17656
17657        cx.notify();
17658    }
17659
17660    pub fn toggle_minimap(
17661        &mut self,
17662        _: &ToggleMinimap,
17663        window: &mut Window,
17664        cx: &mut Context<Editor>,
17665    ) {
17666        if self.supports_minimap(cx) {
17667            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17668        }
17669    }
17670
17671    fn refresh_inline_diagnostics(
17672        &mut self,
17673        debounce: bool,
17674        window: &mut Window,
17675        cx: &mut Context<Self>,
17676    ) {
17677        let max_severity = ProjectSettings::get_global(cx)
17678            .diagnostics
17679            .inline
17680            .max_severity
17681            .unwrap_or(self.diagnostics_max_severity);
17682
17683        if !self.inline_diagnostics_enabled()
17684            || !self.show_inline_diagnostics
17685            || max_severity == DiagnosticSeverity::Off
17686        {
17687            self.inline_diagnostics_update = Task::ready(());
17688            self.inline_diagnostics.clear();
17689            return;
17690        }
17691
17692        let debounce_ms = ProjectSettings::get_global(cx)
17693            .diagnostics
17694            .inline
17695            .update_debounce_ms;
17696        let debounce = if debounce && debounce_ms > 0 {
17697            Some(Duration::from_millis(debounce_ms))
17698        } else {
17699            None
17700        };
17701        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17702            if let Some(debounce) = debounce {
17703                cx.background_executor().timer(debounce).await;
17704            }
17705            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17706                editor
17707                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17708                    .ok()
17709            }) else {
17710                return;
17711            };
17712
17713            let new_inline_diagnostics = cx
17714                .background_spawn(async move {
17715                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17716                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17717                        let message = diagnostic_entry
17718                            .diagnostic
17719                            .message
17720                            .split_once('\n')
17721                            .map(|(line, _)| line)
17722                            .map(SharedString::new)
17723                            .unwrap_or_else(|| {
17724                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17725                            });
17726                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17727                        let (Ok(i) | Err(i)) = inline_diagnostics
17728                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17729                        inline_diagnostics.insert(
17730                            i,
17731                            (
17732                                start_anchor,
17733                                InlineDiagnostic {
17734                                    message,
17735                                    group_id: diagnostic_entry.diagnostic.group_id,
17736                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17737                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17738                                    severity: diagnostic_entry.diagnostic.severity,
17739                                },
17740                            ),
17741                        );
17742                    }
17743                    inline_diagnostics
17744                })
17745                .await;
17746
17747            editor
17748                .update(cx, |editor, cx| {
17749                    editor.inline_diagnostics = new_inline_diagnostics;
17750                    cx.notify();
17751                })
17752                .ok();
17753        });
17754    }
17755
17756    fn pull_diagnostics(
17757        &mut self,
17758        buffer_id: Option<BufferId>,
17759        window: &Window,
17760        cx: &mut Context<Self>,
17761    ) -> Option<()> {
17762        if !self.mode().is_full() {
17763            return None;
17764        }
17765        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17766            .diagnostics
17767            .lsp_pull_diagnostics;
17768        if !pull_diagnostics_settings.enabled {
17769            return None;
17770        }
17771        let project = self.project()?.downgrade();
17772        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17773        let mut buffers = self.buffer.read(cx).all_buffers();
17774        if let Some(buffer_id) = buffer_id {
17775            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17776        }
17777
17778        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17779            cx.background_executor().timer(debounce).await;
17780
17781            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17782                buffers
17783                    .into_iter()
17784                    .filter_map(|buffer| {
17785                        project
17786                            .update(cx, |project, cx| {
17787                                project.lsp_store().update(cx, |lsp_store, cx| {
17788                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17789                                })
17790                            })
17791                            .ok()
17792                    })
17793                    .collect::<FuturesUnordered<_>>()
17794            }) else {
17795                return;
17796            };
17797
17798            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17799                match pull_task {
17800                    Ok(()) => {
17801                        if editor
17802                            .update_in(cx, |editor, window, cx| {
17803                                editor.update_diagnostics_state(window, cx);
17804                            })
17805                            .is_err()
17806                        {
17807                            return;
17808                        }
17809                    }
17810                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17811                }
17812            }
17813        });
17814
17815        Some(())
17816    }
17817
17818    pub fn set_selections_from_remote(
17819        &mut self,
17820        selections: Vec<Selection<Anchor>>,
17821        pending_selection: Option<Selection<Anchor>>,
17822        window: &mut Window,
17823        cx: &mut Context<Self>,
17824    ) {
17825        let old_cursor_position = self.selections.newest_anchor().head();
17826        self.selections.change_with(cx, |s| {
17827            s.select_anchors(selections);
17828            if let Some(pending_selection) = pending_selection {
17829                s.set_pending(pending_selection, SelectMode::Character);
17830            } else {
17831                s.clear_pending();
17832            }
17833        });
17834        self.selections_did_change(
17835            false,
17836            &old_cursor_position,
17837            SelectionEffects::default(),
17838            window,
17839            cx,
17840        );
17841    }
17842
17843    pub fn transact(
17844        &mut self,
17845        window: &mut Window,
17846        cx: &mut Context<Self>,
17847        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17848    ) -> Option<TransactionId> {
17849        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17850            this.start_transaction_at(Instant::now(), window, cx);
17851            update(this, window, cx);
17852            this.end_transaction_at(Instant::now(), cx)
17853        })
17854    }
17855
17856    pub fn start_transaction_at(
17857        &mut self,
17858        now: Instant,
17859        window: &mut Window,
17860        cx: &mut Context<Self>,
17861    ) -> Option<TransactionId> {
17862        self.end_selection(window, cx);
17863        if let Some(tx_id) = self
17864            .buffer
17865            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17866        {
17867            self.selection_history
17868                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17869            cx.emit(EditorEvent::TransactionBegun {
17870                transaction_id: tx_id,
17871            });
17872            Some(tx_id)
17873        } else {
17874            None
17875        }
17876    }
17877
17878    pub fn end_transaction_at(
17879        &mut self,
17880        now: Instant,
17881        cx: &mut Context<Self>,
17882    ) -> Option<TransactionId> {
17883        if let Some(transaction_id) = self
17884            .buffer
17885            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17886        {
17887            if let Some((_, end_selections)) =
17888                self.selection_history.transaction_mut(transaction_id)
17889            {
17890                *end_selections = Some(self.selections.disjoint_anchors_arc());
17891            } else {
17892                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17893            }
17894
17895            cx.emit(EditorEvent::Edited { transaction_id });
17896            Some(transaction_id)
17897        } else {
17898            None
17899        }
17900    }
17901
17902    pub fn modify_transaction_selection_history(
17903        &mut self,
17904        transaction_id: TransactionId,
17905        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17906    ) -> bool {
17907        self.selection_history
17908            .transaction_mut(transaction_id)
17909            .map(modify)
17910            .is_some()
17911    }
17912
17913    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17914        if self.selection_mark_mode {
17915            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17916                s.move_with(|_, sel| {
17917                    sel.collapse_to(sel.head(), SelectionGoal::None);
17918                });
17919            })
17920        }
17921        self.selection_mark_mode = true;
17922        cx.notify();
17923    }
17924
17925    pub fn swap_selection_ends(
17926        &mut self,
17927        _: &actions::SwapSelectionEnds,
17928        window: &mut Window,
17929        cx: &mut Context<Self>,
17930    ) {
17931        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17932            s.move_with(|_, sel| {
17933                if sel.start != sel.end {
17934                    sel.reversed = !sel.reversed
17935                }
17936            });
17937        });
17938        self.request_autoscroll(Autoscroll::newest(), cx);
17939        cx.notify();
17940    }
17941
17942    pub fn toggle_focus(
17943        workspace: &mut Workspace,
17944        _: &actions::ToggleFocus,
17945        window: &mut Window,
17946        cx: &mut Context<Workspace>,
17947    ) {
17948        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17949            return;
17950        };
17951        workspace.activate_item(&item, true, true, window, cx);
17952    }
17953
17954    pub fn toggle_fold(
17955        &mut self,
17956        _: &actions::ToggleFold,
17957        window: &mut Window,
17958        cx: &mut Context<Self>,
17959    ) {
17960        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
17961            let selection = self.selections.newest::<Point>(cx);
17962
17963            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17964            let range = if selection.is_empty() {
17965                let point = selection.head().to_display_point(&display_map);
17966                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17967                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17968                    .to_point(&display_map);
17969                start..end
17970            } else {
17971                selection.range()
17972            };
17973            if display_map.folds_in_range(range).next().is_some() {
17974                self.unfold_lines(&Default::default(), window, cx)
17975            } else {
17976                self.fold(&Default::default(), window, cx)
17977            }
17978        } else {
17979            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17980            let buffer_ids: HashSet<_> = self
17981                .selections
17982                .disjoint_anchor_ranges()
17983                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17984                .collect();
17985
17986            let should_unfold = buffer_ids
17987                .iter()
17988                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17989
17990            for buffer_id in buffer_ids {
17991                if should_unfold {
17992                    self.unfold_buffer(buffer_id, cx);
17993                } else {
17994                    self.fold_buffer(buffer_id, cx);
17995                }
17996            }
17997        }
17998    }
17999
18000    pub fn toggle_fold_recursive(
18001        &mut self,
18002        _: &actions::ToggleFoldRecursive,
18003        window: &mut Window,
18004        cx: &mut Context<Self>,
18005    ) {
18006        let selection = self.selections.newest::<Point>(cx);
18007
18008        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18009        let range = if selection.is_empty() {
18010            let point = selection.head().to_display_point(&display_map);
18011            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18012            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18013                .to_point(&display_map);
18014            start..end
18015        } else {
18016            selection.range()
18017        };
18018        if display_map.folds_in_range(range).next().is_some() {
18019            self.unfold_recursive(&Default::default(), window, cx)
18020        } else {
18021            self.fold_recursive(&Default::default(), window, cx)
18022        }
18023    }
18024
18025    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18026        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18027            let mut to_fold = Vec::new();
18028            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18029            let selections = self.selections.all_adjusted(cx);
18030
18031            for selection in selections {
18032                let range = selection.range().sorted();
18033                let buffer_start_row = range.start.row;
18034
18035                if range.start.row != range.end.row {
18036                    let mut found = false;
18037                    let mut row = range.start.row;
18038                    while row <= range.end.row {
18039                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18040                        {
18041                            found = true;
18042                            row = crease.range().end.row + 1;
18043                            to_fold.push(crease);
18044                        } else {
18045                            row += 1
18046                        }
18047                    }
18048                    if found {
18049                        continue;
18050                    }
18051                }
18052
18053                for row in (0..=range.start.row).rev() {
18054                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18055                        && crease.range().end.row >= buffer_start_row
18056                    {
18057                        to_fold.push(crease);
18058                        if row <= range.start.row {
18059                            break;
18060                        }
18061                    }
18062                }
18063            }
18064
18065            self.fold_creases(to_fold, true, window, cx);
18066        } else {
18067            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18068            let buffer_ids = self
18069                .selections
18070                .disjoint_anchor_ranges()
18071                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18072                .collect::<HashSet<_>>();
18073            for buffer_id in buffer_ids {
18074                self.fold_buffer(buffer_id, cx);
18075            }
18076        }
18077    }
18078
18079    pub fn toggle_fold_all(
18080        &mut self,
18081        _: &actions::ToggleFoldAll,
18082        window: &mut Window,
18083        cx: &mut Context<Self>,
18084    ) {
18085        if self.buffer.read(cx).is_singleton() {
18086            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18087            let has_folds = display_map
18088                .folds_in_range(0..display_map.buffer_snapshot().len())
18089                .next()
18090                .is_some();
18091
18092            if has_folds {
18093                self.unfold_all(&actions::UnfoldAll, window, cx);
18094            } else {
18095                self.fold_all(&actions::FoldAll, window, cx);
18096            }
18097        } else {
18098            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18099            let should_unfold = buffer_ids
18100                .iter()
18101                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18102
18103            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18104                editor
18105                    .update_in(cx, |editor, _, cx| {
18106                        for buffer_id in buffer_ids {
18107                            if should_unfold {
18108                                editor.unfold_buffer(buffer_id, cx);
18109                            } else {
18110                                editor.fold_buffer(buffer_id, cx);
18111                            }
18112                        }
18113                    })
18114                    .ok();
18115            });
18116        }
18117    }
18118
18119    fn fold_at_level(
18120        &mut self,
18121        fold_at: &FoldAtLevel,
18122        window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        if !self.buffer.read(cx).is_singleton() {
18126            return;
18127        }
18128
18129        let fold_at_level = fold_at.0;
18130        let snapshot = self.buffer.read(cx).snapshot(cx);
18131        let mut to_fold = Vec::new();
18132        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18133
18134        let row_ranges_to_keep: Vec<Range<u32>> = self
18135            .selections
18136            .all::<Point>(cx)
18137            .into_iter()
18138            .map(|sel| sel.start.row..sel.end.row)
18139            .collect();
18140
18141        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18142            while start_row < end_row {
18143                match self
18144                    .snapshot(window, cx)
18145                    .crease_for_buffer_row(MultiBufferRow(start_row))
18146                {
18147                    Some(crease) => {
18148                        let nested_start_row = crease.range().start.row + 1;
18149                        let nested_end_row = crease.range().end.row;
18150
18151                        if current_level < fold_at_level {
18152                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18153                        } else if current_level == fold_at_level {
18154                            // Fold iff there is no selection completely contained within the fold region
18155                            if !row_ranges_to_keep.iter().any(|selection| {
18156                                selection.end >= nested_start_row
18157                                    && selection.start <= nested_end_row
18158                            }) {
18159                                to_fold.push(crease);
18160                            }
18161                        }
18162
18163                        start_row = nested_end_row + 1;
18164                    }
18165                    None => start_row += 1,
18166                }
18167            }
18168        }
18169
18170        self.fold_creases(to_fold, true, window, cx);
18171    }
18172
18173    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18174        if self.buffer.read(cx).is_singleton() {
18175            let mut fold_ranges = Vec::new();
18176            let snapshot = self.buffer.read(cx).snapshot(cx);
18177
18178            for row in 0..snapshot.max_row().0 {
18179                if let Some(foldable_range) = self
18180                    .snapshot(window, cx)
18181                    .crease_for_buffer_row(MultiBufferRow(row))
18182                {
18183                    fold_ranges.push(foldable_range);
18184                }
18185            }
18186
18187            self.fold_creases(fold_ranges, true, window, cx);
18188        } else {
18189            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18190                editor
18191                    .update_in(cx, |editor, _, cx| {
18192                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18193                            editor.fold_buffer(buffer_id, cx);
18194                        }
18195                    })
18196                    .ok();
18197            });
18198        }
18199    }
18200
18201    pub fn fold_function_bodies(
18202        &mut self,
18203        _: &actions::FoldFunctionBodies,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        let snapshot = self.buffer.read(cx).snapshot(cx);
18208
18209        let ranges = snapshot
18210            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18211            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18212            .collect::<Vec<_>>();
18213
18214        let creases = ranges
18215            .into_iter()
18216            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18217            .collect();
18218
18219        self.fold_creases(creases, true, window, cx);
18220    }
18221
18222    pub fn fold_recursive(
18223        &mut self,
18224        _: &actions::FoldRecursive,
18225        window: &mut Window,
18226        cx: &mut Context<Self>,
18227    ) {
18228        let mut to_fold = Vec::new();
18229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18230        let selections = self.selections.all_adjusted(cx);
18231
18232        for selection in selections {
18233            let range = selection.range().sorted();
18234            let buffer_start_row = range.start.row;
18235
18236            if range.start.row != range.end.row {
18237                let mut found = false;
18238                for row in range.start.row..=range.end.row {
18239                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18240                        found = true;
18241                        to_fold.push(crease);
18242                    }
18243                }
18244                if found {
18245                    continue;
18246                }
18247            }
18248
18249            for row in (0..=range.start.row).rev() {
18250                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18251                    if crease.range().end.row >= buffer_start_row {
18252                        to_fold.push(crease);
18253                    } else {
18254                        break;
18255                    }
18256                }
18257            }
18258        }
18259
18260        self.fold_creases(to_fold, true, window, cx);
18261    }
18262
18263    pub fn fold_at(
18264        &mut self,
18265        buffer_row: MultiBufferRow,
18266        window: &mut Window,
18267        cx: &mut Context<Self>,
18268    ) {
18269        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18270
18271        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18272            let autoscroll = self
18273                .selections
18274                .all::<Point>(cx)
18275                .iter()
18276                .any(|selection| crease.range().overlaps(&selection.range()));
18277
18278            self.fold_creases(vec![crease], autoscroll, window, cx);
18279        }
18280    }
18281
18282    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18283        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18284            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18285            let buffer = display_map.buffer_snapshot();
18286            let selections = self.selections.all::<Point>(cx);
18287            let ranges = selections
18288                .iter()
18289                .map(|s| {
18290                    let range = s.display_range(&display_map).sorted();
18291                    let mut start = range.start.to_point(&display_map);
18292                    let mut end = range.end.to_point(&display_map);
18293                    start.column = 0;
18294                    end.column = buffer.line_len(MultiBufferRow(end.row));
18295                    start..end
18296                })
18297                .collect::<Vec<_>>();
18298
18299            self.unfold_ranges(&ranges, true, true, cx);
18300        } else {
18301            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18302            let buffer_ids = self
18303                .selections
18304                .disjoint_anchor_ranges()
18305                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18306                .collect::<HashSet<_>>();
18307            for buffer_id in buffer_ids {
18308                self.unfold_buffer(buffer_id, cx);
18309            }
18310        }
18311    }
18312
18313    pub fn unfold_recursive(
18314        &mut self,
18315        _: &UnfoldRecursive,
18316        _window: &mut Window,
18317        cx: &mut Context<Self>,
18318    ) {
18319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18320        let selections = self.selections.all::<Point>(cx);
18321        let ranges = selections
18322            .iter()
18323            .map(|s| {
18324                let mut range = s.display_range(&display_map).sorted();
18325                *range.start.column_mut() = 0;
18326                *range.end.column_mut() = display_map.line_len(range.end.row());
18327                let start = range.start.to_point(&display_map);
18328                let end = range.end.to_point(&display_map);
18329                start..end
18330            })
18331            .collect::<Vec<_>>();
18332
18333        self.unfold_ranges(&ranges, true, true, cx);
18334    }
18335
18336    pub fn unfold_at(
18337        &mut self,
18338        buffer_row: MultiBufferRow,
18339        _window: &mut Window,
18340        cx: &mut Context<Self>,
18341    ) {
18342        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18343
18344        let intersection_range = Point::new(buffer_row.0, 0)
18345            ..Point::new(
18346                buffer_row.0,
18347                display_map.buffer_snapshot().line_len(buffer_row),
18348            );
18349
18350        let autoscroll = self
18351            .selections
18352            .all::<Point>(cx)
18353            .iter()
18354            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18355
18356        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18357    }
18358
18359    pub fn unfold_all(
18360        &mut self,
18361        _: &actions::UnfoldAll,
18362        _window: &mut Window,
18363        cx: &mut Context<Self>,
18364    ) {
18365        if self.buffer.read(cx).is_singleton() {
18366            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18367            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18368        } else {
18369            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18370                editor
18371                    .update(cx, |editor, cx| {
18372                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18373                            editor.unfold_buffer(buffer_id, cx);
18374                        }
18375                    })
18376                    .ok();
18377            });
18378        }
18379    }
18380
18381    pub fn fold_selected_ranges(
18382        &mut self,
18383        _: &FoldSelectedRanges,
18384        window: &mut Window,
18385        cx: &mut Context<Self>,
18386    ) {
18387        let selections = self.selections.all_adjusted(cx);
18388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18389        let ranges = selections
18390            .into_iter()
18391            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18392            .collect::<Vec<_>>();
18393        self.fold_creases(ranges, true, window, cx);
18394    }
18395
18396    pub fn fold_ranges<T: ToOffset + Clone>(
18397        &mut self,
18398        ranges: Vec<Range<T>>,
18399        auto_scroll: bool,
18400        window: &mut Window,
18401        cx: &mut Context<Self>,
18402    ) {
18403        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18404        let ranges = ranges
18405            .into_iter()
18406            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18407            .collect::<Vec<_>>();
18408        self.fold_creases(ranges, auto_scroll, window, cx);
18409    }
18410
18411    pub fn fold_creases<T: ToOffset + Clone>(
18412        &mut self,
18413        creases: Vec<Crease<T>>,
18414        auto_scroll: bool,
18415        _window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        if creases.is_empty() {
18419            return;
18420        }
18421
18422        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18423
18424        if auto_scroll {
18425            self.request_autoscroll(Autoscroll::fit(), cx);
18426        }
18427
18428        cx.notify();
18429
18430        self.scrollbar_marker_state.dirty = true;
18431        self.folds_did_change(cx);
18432    }
18433
18434    /// Removes any folds whose ranges intersect any of the given ranges.
18435    pub fn unfold_ranges<T: ToOffset + Clone>(
18436        &mut self,
18437        ranges: &[Range<T>],
18438        inclusive: bool,
18439        auto_scroll: bool,
18440        cx: &mut Context<Self>,
18441    ) {
18442        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18443            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18444        });
18445        self.folds_did_change(cx);
18446    }
18447
18448    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18449        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18450            return;
18451        }
18452        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18453        self.display_map.update(cx, |display_map, cx| {
18454            display_map.fold_buffers([buffer_id], cx)
18455        });
18456        cx.emit(EditorEvent::BufferFoldToggled {
18457            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18458            folded: true,
18459        });
18460        cx.notify();
18461    }
18462
18463    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18464        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18465            return;
18466        }
18467        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18468        self.display_map.update(cx, |display_map, cx| {
18469            display_map.unfold_buffers([buffer_id], cx);
18470        });
18471        cx.emit(EditorEvent::BufferFoldToggled {
18472            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18473            folded: false,
18474        });
18475        cx.notify();
18476    }
18477
18478    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18479        self.display_map.read(cx).is_buffer_folded(buffer)
18480    }
18481
18482    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18483        self.display_map.read(cx).folded_buffers()
18484    }
18485
18486    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18487        self.display_map.update(cx, |display_map, cx| {
18488            display_map.disable_header_for_buffer(buffer_id, cx);
18489        });
18490        cx.notify();
18491    }
18492
18493    /// Removes any folds with the given ranges.
18494    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18495        &mut self,
18496        ranges: &[Range<T>],
18497        type_id: TypeId,
18498        auto_scroll: bool,
18499        cx: &mut Context<Self>,
18500    ) {
18501        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18502            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18503        });
18504        self.folds_did_change(cx);
18505    }
18506
18507    fn remove_folds_with<T: ToOffset + Clone>(
18508        &mut self,
18509        ranges: &[Range<T>],
18510        auto_scroll: bool,
18511        cx: &mut Context<Self>,
18512        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18513    ) {
18514        if ranges.is_empty() {
18515            return;
18516        }
18517
18518        let mut buffers_affected = HashSet::default();
18519        let multi_buffer = self.buffer().read(cx);
18520        for range in ranges {
18521            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18522                buffers_affected.insert(buffer.read(cx).remote_id());
18523            };
18524        }
18525
18526        self.display_map.update(cx, update);
18527
18528        if auto_scroll {
18529            self.request_autoscroll(Autoscroll::fit(), cx);
18530        }
18531
18532        cx.notify();
18533        self.scrollbar_marker_state.dirty = true;
18534        self.active_indent_guides_state.dirty = true;
18535    }
18536
18537    pub fn update_renderer_widths(
18538        &mut self,
18539        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18540        cx: &mut Context<Self>,
18541    ) -> bool {
18542        self.display_map
18543            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18544    }
18545
18546    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18547        self.display_map.read(cx).fold_placeholder.clone()
18548    }
18549
18550    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18551        self.buffer.update(cx, |buffer, cx| {
18552            buffer.set_all_diff_hunks_expanded(cx);
18553        });
18554    }
18555
18556    pub fn expand_all_diff_hunks(
18557        &mut self,
18558        _: &ExpandAllDiffHunks,
18559        _window: &mut Window,
18560        cx: &mut Context<Self>,
18561    ) {
18562        self.buffer.update(cx, |buffer, cx| {
18563            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18564        });
18565    }
18566
18567    pub fn toggle_selected_diff_hunks(
18568        &mut self,
18569        _: &ToggleSelectedDiffHunks,
18570        _window: &mut Window,
18571        cx: &mut Context<Self>,
18572    ) {
18573        let ranges: Vec<_> = self
18574            .selections
18575            .disjoint_anchors()
18576            .iter()
18577            .map(|s| s.range())
18578            .collect();
18579        self.toggle_diff_hunks_in_ranges(ranges, cx);
18580    }
18581
18582    pub fn diff_hunks_in_ranges<'a>(
18583        &'a self,
18584        ranges: &'a [Range<Anchor>],
18585        buffer: &'a MultiBufferSnapshot,
18586    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18587        ranges.iter().flat_map(move |range| {
18588            let end_excerpt_id = range.end.excerpt_id;
18589            let range = range.to_point(buffer);
18590            let mut peek_end = range.end;
18591            if range.end.row < buffer.max_row().0 {
18592                peek_end = Point::new(range.end.row + 1, 0);
18593            }
18594            buffer
18595                .diff_hunks_in_range(range.start..peek_end)
18596                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18597        })
18598    }
18599
18600    pub fn has_stageable_diff_hunks_in_ranges(
18601        &self,
18602        ranges: &[Range<Anchor>],
18603        snapshot: &MultiBufferSnapshot,
18604    ) -> bool {
18605        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18606        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18607    }
18608
18609    pub fn toggle_staged_selected_diff_hunks(
18610        &mut self,
18611        _: &::git::ToggleStaged,
18612        _: &mut Window,
18613        cx: &mut Context<Self>,
18614    ) {
18615        let snapshot = self.buffer.read(cx).snapshot(cx);
18616        let ranges: Vec<_> = self
18617            .selections
18618            .disjoint_anchors()
18619            .iter()
18620            .map(|s| s.range())
18621            .collect();
18622        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18623        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18624    }
18625
18626    pub fn set_render_diff_hunk_controls(
18627        &mut self,
18628        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18629        cx: &mut Context<Self>,
18630    ) {
18631        self.render_diff_hunk_controls = render_diff_hunk_controls;
18632        cx.notify();
18633    }
18634
18635    pub fn stage_and_next(
18636        &mut self,
18637        _: &::git::StageAndNext,
18638        window: &mut Window,
18639        cx: &mut Context<Self>,
18640    ) {
18641        self.do_stage_or_unstage_and_next(true, window, cx);
18642    }
18643
18644    pub fn unstage_and_next(
18645        &mut self,
18646        _: &::git::UnstageAndNext,
18647        window: &mut Window,
18648        cx: &mut Context<Self>,
18649    ) {
18650        self.do_stage_or_unstage_and_next(false, window, cx);
18651    }
18652
18653    pub fn stage_or_unstage_diff_hunks(
18654        &mut self,
18655        stage: bool,
18656        ranges: Vec<Range<Anchor>>,
18657        cx: &mut Context<Self>,
18658    ) {
18659        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18660        cx.spawn(async move |this, cx| {
18661            task.await?;
18662            this.update(cx, |this, cx| {
18663                let snapshot = this.buffer.read(cx).snapshot(cx);
18664                let chunk_by = this
18665                    .diff_hunks_in_ranges(&ranges, &snapshot)
18666                    .chunk_by(|hunk| hunk.buffer_id);
18667                for (buffer_id, hunks) in &chunk_by {
18668                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18669                }
18670            })
18671        })
18672        .detach_and_log_err(cx);
18673    }
18674
18675    fn save_buffers_for_ranges_if_needed(
18676        &mut self,
18677        ranges: &[Range<Anchor>],
18678        cx: &mut Context<Editor>,
18679    ) -> Task<Result<()>> {
18680        let multibuffer = self.buffer.read(cx);
18681        let snapshot = multibuffer.read(cx);
18682        let buffer_ids: HashSet<_> = ranges
18683            .iter()
18684            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18685            .collect();
18686        drop(snapshot);
18687
18688        let mut buffers = HashSet::default();
18689        for buffer_id in buffer_ids {
18690            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18691                let buffer = buffer_entity.read(cx);
18692                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18693                {
18694                    buffers.insert(buffer_entity);
18695                }
18696            }
18697        }
18698
18699        if let Some(project) = &self.project {
18700            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18701        } else {
18702            Task::ready(Ok(()))
18703        }
18704    }
18705
18706    fn do_stage_or_unstage_and_next(
18707        &mut self,
18708        stage: bool,
18709        window: &mut Window,
18710        cx: &mut Context<Self>,
18711    ) {
18712        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18713
18714        if ranges.iter().any(|range| range.start != range.end) {
18715            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18716            return;
18717        }
18718
18719        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18720        let snapshot = self.snapshot(window, cx);
18721        let position = self.selections.newest::<Point>(cx).head();
18722        let mut row = snapshot
18723            .buffer_snapshot()
18724            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18725            .find(|hunk| hunk.row_range.start.0 > position.row)
18726            .map(|hunk| hunk.row_range.start);
18727
18728        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18729        // Outside of the project diff editor, wrap around to the beginning.
18730        if !all_diff_hunks_expanded {
18731            row = row.or_else(|| {
18732                snapshot
18733                    .buffer_snapshot()
18734                    .diff_hunks_in_range(Point::zero()..position)
18735                    .find(|hunk| hunk.row_range.end.0 < position.row)
18736                    .map(|hunk| hunk.row_range.start)
18737            });
18738        }
18739
18740        if let Some(row) = row {
18741            let destination = Point::new(row.0, 0);
18742            let autoscroll = Autoscroll::center();
18743
18744            self.unfold_ranges(&[destination..destination], false, false, cx);
18745            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18746                s.select_ranges([destination..destination]);
18747            });
18748        }
18749    }
18750
18751    fn do_stage_or_unstage(
18752        &self,
18753        stage: bool,
18754        buffer_id: BufferId,
18755        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18756        cx: &mut App,
18757    ) -> Option<()> {
18758        let project = self.project()?;
18759        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18760        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18761        let buffer_snapshot = buffer.read(cx).snapshot();
18762        let file_exists = buffer_snapshot
18763            .file()
18764            .is_some_and(|file| file.disk_state().exists());
18765        diff.update(cx, |diff, cx| {
18766            diff.stage_or_unstage_hunks(
18767                stage,
18768                &hunks
18769                    .map(|hunk| buffer_diff::DiffHunk {
18770                        buffer_range: hunk.buffer_range,
18771                        diff_base_byte_range: hunk.diff_base_byte_range,
18772                        secondary_status: hunk.secondary_status,
18773                        range: Point::zero()..Point::zero(), // unused
18774                    })
18775                    .collect::<Vec<_>>(),
18776                &buffer_snapshot,
18777                file_exists,
18778                cx,
18779            )
18780        });
18781        None
18782    }
18783
18784    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18785        let ranges: Vec<_> = self
18786            .selections
18787            .disjoint_anchors()
18788            .iter()
18789            .map(|s| s.range())
18790            .collect();
18791        self.buffer
18792            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18793    }
18794
18795    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18796        self.buffer.update(cx, |buffer, cx| {
18797            let ranges = vec![Anchor::min()..Anchor::max()];
18798            if !buffer.all_diff_hunks_expanded()
18799                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18800            {
18801                buffer.collapse_diff_hunks(ranges, cx);
18802                true
18803            } else {
18804                false
18805            }
18806        })
18807    }
18808
18809    fn toggle_diff_hunks_in_ranges(
18810        &mut self,
18811        ranges: Vec<Range<Anchor>>,
18812        cx: &mut Context<Editor>,
18813    ) {
18814        self.buffer.update(cx, |buffer, cx| {
18815            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18816            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18817        })
18818    }
18819
18820    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18821        self.buffer.update(cx, |buffer, cx| {
18822            let snapshot = buffer.snapshot(cx);
18823            let excerpt_id = range.end.excerpt_id;
18824            let point_range = range.to_point(&snapshot);
18825            let expand = !buffer.single_hunk_is_expanded(range, cx);
18826            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18827        })
18828    }
18829
18830    pub(crate) fn apply_all_diff_hunks(
18831        &mut self,
18832        _: &ApplyAllDiffHunks,
18833        window: &mut Window,
18834        cx: &mut Context<Self>,
18835    ) {
18836        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18837
18838        let buffers = self.buffer.read(cx).all_buffers();
18839        for branch_buffer in buffers {
18840            branch_buffer.update(cx, |branch_buffer, cx| {
18841                branch_buffer.merge_into_base(Vec::new(), cx);
18842            });
18843        }
18844
18845        if let Some(project) = self.project.clone() {
18846            self.save(
18847                SaveOptions {
18848                    format: true,
18849                    autosave: false,
18850                },
18851                project,
18852                window,
18853                cx,
18854            )
18855            .detach_and_log_err(cx);
18856        }
18857    }
18858
18859    pub(crate) fn apply_selected_diff_hunks(
18860        &mut self,
18861        _: &ApplyDiffHunk,
18862        window: &mut Window,
18863        cx: &mut Context<Self>,
18864    ) {
18865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18866        let snapshot = self.snapshot(window, cx);
18867        let hunks = snapshot.hunks_for_ranges(
18868            self.selections
18869                .all(cx)
18870                .into_iter()
18871                .map(|selection| selection.range()),
18872        );
18873        let mut ranges_by_buffer = HashMap::default();
18874        self.transact(window, cx, |editor, _window, cx| {
18875            for hunk in hunks {
18876                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18877                    ranges_by_buffer
18878                        .entry(buffer.clone())
18879                        .or_insert_with(Vec::new)
18880                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18881                }
18882            }
18883
18884            for (buffer, ranges) in ranges_by_buffer {
18885                buffer.update(cx, |buffer, cx| {
18886                    buffer.merge_into_base(ranges, cx);
18887                });
18888            }
18889        });
18890
18891        if let Some(project) = self.project.clone() {
18892            self.save(
18893                SaveOptions {
18894                    format: true,
18895                    autosave: false,
18896                },
18897                project,
18898                window,
18899                cx,
18900            )
18901            .detach_and_log_err(cx);
18902        }
18903    }
18904
18905    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18906        if hovered != self.gutter_hovered {
18907            self.gutter_hovered = hovered;
18908            cx.notify();
18909        }
18910    }
18911
18912    pub fn insert_blocks(
18913        &mut self,
18914        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18915        autoscroll: Option<Autoscroll>,
18916        cx: &mut Context<Self>,
18917    ) -> Vec<CustomBlockId> {
18918        let blocks = self
18919            .display_map
18920            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18921        if let Some(autoscroll) = autoscroll {
18922            self.request_autoscroll(autoscroll, cx);
18923        }
18924        cx.notify();
18925        blocks
18926    }
18927
18928    pub fn resize_blocks(
18929        &mut self,
18930        heights: HashMap<CustomBlockId, u32>,
18931        autoscroll: Option<Autoscroll>,
18932        cx: &mut Context<Self>,
18933    ) {
18934        self.display_map
18935            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18936        if let Some(autoscroll) = autoscroll {
18937            self.request_autoscroll(autoscroll, cx);
18938        }
18939        cx.notify();
18940    }
18941
18942    pub fn replace_blocks(
18943        &mut self,
18944        renderers: HashMap<CustomBlockId, RenderBlock>,
18945        autoscroll: Option<Autoscroll>,
18946        cx: &mut Context<Self>,
18947    ) {
18948        self.display_map
18949            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18950        if let Some(autoscroll) = autoscroll {
18951            self.request_autoscroll(autoscroll, cx);
18952        }
18953        cx.notify();
18954    }
18955
18956    pub fn remove_blocks(
18957        &mut self,
18958        block_ids: HashSet<CustomBlockId>,
18959        autoscroll: Option<Autoscroll>,
18960        cx: &mut Context<Self>,
18961    ) {
18962        self.display_map.update(cx, |display_map, cx| {
18963            display_map.remove_blocks(block_ids, cx)
18964        });
18965        if let Some(autoscroll) = autoscroll {
18966            self.request_autoscroll(autoscroll, cx);
18967        }
18968        cx.notify();
18969    }
18970
18971    pub fn row_for_block(
18972        &self,
18973        block_id: CustomBlockId,
18974        cx: &mut Context<Self>,
18975    ) -> Option<DisplayRow> {
18976        self.display_map
18977            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18978    }
18979
18980    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18981        self.focused_block = Some(focused_block);
18982    }
18983
18984    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18985        self.focused_block.take()
18986    }
18987
18988    pub fn insert_creases(
18989        &mut self,
18990        creases: impl IntoIterator<Item = Crease<Anchor>>,
18991        cx: &mut Context<Self>,
18992    ) -> Vec<CreaseId> {
18993        self.display_map
18994            .update(cx, |map, cx| map.insert_creases(creases, cx))
18995    }
18996
18997    pub fn remove_creases(
18998        &mut self,
18999        ids: impl IntoIterator<Item = CreaseId>,
19000        cx: &mut Context<Self>,
19001    ) -> Vec<(CreaseId, Range<Anchor>)> {
19002        self.display_map
19003            .update(cx, |map, cx| map.remove_creases(ids, cx))
19004    }
19005
19006    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19007        self.display_map
19008            .update(cx, |map, cx| map.snapshot(cx))
19009            .longest_row()
19010    }
19011
19012    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19013        self.display_map
19014            .update(cx, |map, cx| map.snapshot(cx))
19015            .max_point()
19016    }
19017
19018    pub fn text(&self, cx: &App) -> String {
19019        self.buffer.read(cx).read(cx).text()
19020    }
19021
19022    pub fn is_empty(&self, cx: &App) -> bool {
19023        self.buffer.read(cx).read(cx).is_empty()
19024    }
19025
19026    pub fn text_option(&self, cx: &App) -> Option<String> {
19027        let text = self.text(cx);
19028        let text = text.trim();
19029
19030        if text.is_empty() {
19031            return None;
19032        }
19033
19034        Some(text.to_string())
19035    }
19036
19037    pub fn set_text(
19038        &mut self,
19039        text: impl Into<Arc<str>>,
19040        window: &mut Window,
19041        cx: &mut Context<Self>,
19042    ) {
19043        self.transact(window, cx, |this, _, cx| {
19044            this.buffer
19045                .read(cx)
19046                .as_singleton()
19047                .expect("you can only call set_text on editors for singleton buffers")
19048                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19049        });
19050    }
19051
19052    pub fn display_text(&self, cx: &mut App) -> String {
19053        self.display_map
19054            .update(cx, |map, cx| map.snapshot(cx))
19055            .text()
19056    }
19057
19058    fn create_minimap(
19059        &self,
19060        minimap_settings: MinimapSettings,
19061        window: &mut Window,
19062        cx: &mut Context<Self>,
19063    ) -> Option<Entity<Self>> {
19064        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19065            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19066    }
19067
19068    fn initialize_new_minimap(
19069        &self,
19070        minimap_settings: MinimapSettings,
19071        window: &mut Window,
19072        cx: &mut Context<Self>,
19073    ) -> Entity<Self> {
19074        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19075
19076        let mut minimap = Editor::new_internal(
19077            EditorMode::Minimap {
19078                parent: cx.weak_entity(),
19079            },
19080            self.buffer.clone(),
19081            None,
19082            Some(self.display_map.clone()),
19083            window,
19084            cx,
19085        );
19086        minimap.scroll_manager.clone_state(&self.scroll_manager);
19087        minimap.set_text_style_refinement(TextStyleRefinement {
19088            font_size: Some(MINIMAP_FONT_SIZE),
19089            font_weight: Some(MINIMAP_FONT_WEIGHT),
19090            ..Default::default()
19091        });
19092        minimap.update_minimap_configuration(minimap_settings, cx);
19093        cx.new(|_| minimap)
19094    }
19095
19096    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19097        let current_line_highlight = minimap_settings
19098            .current_line_highlight
19099            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19100        self.set_current_line_highlight(Some(current_line_highlight));
19101    }
19102
19103    pub fn minimap(&self) -> Option<&Entity<Self>> {
19104        self.minimap
19105            .as_ref()
19106            .filter(|_| self.minimap_visibility.visible())
19107    }
19108
19109    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19110        let mut wrap_guides = smallvec![];
19111
19112        if self.show_wrap_guides == Some(false) {
19113            return wrap_guides;
19114        }
19115
19116        let settings = self.buffer.read(cx).language_settings(cx);
19117        if settings.show_wrap_guides {
19118            match self.soft_wrap_mode(cx) {
19119                SoftWrap::Column(soft_wrap) => {
19120                    wrap_guides.push((soft_wrap as usize, true));
19121                }
19122                SoftWrap::Bounded(soft_wrap) => {
19123                    wrap_guides.push((soft_wrap as usize, true));
19124                }
19125                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19126            }
19127            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19128        }
19129
19130        wrap_guides
19131    }
19132
19133    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19134        let settings = self.buffer.read(cx).language_settings(cx);
19135        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19136        match mode {
19137            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19138                SoftWrap::None
19139            }
19140            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19141            language_settings::SoftWrap::PreferredLineLength => {
19142                SoftWrap::Column(settings.preferred_line_length)
19143            }
19144            language_settings::SoftWrap::Bounded => {
19145                SoftWrap::Bounded(settings.preferred_line_length)
19146            }
19147        }
19148    }
19149
19150    pub fn set_soft_wrap_mode(
19151        &mut self,
19152        mode: language_settings::SoftWrap,
19153
19154        cx: &mut Context<Self>,
19155    ) {
19156        self.soft_wrap_mode_override = Some(mode);
19157        cx.notify();
19158    }
19159
19160    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19161        self.hard_wrap = hard_wrap;
19162        cx.notify();
19163    }
19164
19165    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19166        self.text_style_refinement = Some(style);
19167    }
19168
19169    /// called by the Element so we know what style we were most recently rendered with.
19170    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19171        // We intentionally do not inform the display map about the minimap style
19172        // so that wrapping is not recalculated and stays consistent for the editor
19173        // and its linked minimap.
19174        if !self.mode.is_minimap() {
19175            let font = style.text.font();
19176            let font_size = style.text.font_size.to_pixels(window.rem_size());
19177            let display_map = self
19178                .placeholder_display_map
19179                .as_ref()
19180                .filter(|_| self.is_empty(cx))
19181                .unwrap_or(&self.display_map);
19182
19183            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19184        }
19185        self.style = Some(style);
19186    }
19187
19188    pub fn style(&self) -> Option<&EditorStyle> {
19189        self.style.as_ref()
19190    }
19191
19192    // Called by the element. This method is not designed to be called outside of the editor
19193    // element's layout code because it does not notify when rewrapping is computed synchronously.
19194    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19195        if self.is_empty(cx) {
19196            self.placeholder_display_map
19197                .as_ref()
19198                .map_or(false, |display_map| {
19199                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19200                })
19201        } else {
19202            self.display_map
19203                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19204        }
19205    }
19206
19207    pub fn set_soft_wrap(&mut self) {
19208        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19209    }
19210
19211    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19212        if self.soft_wrap_mode_override.is_some() {
19213            self.soft_wrap_mode_override.take();
19214        } else {
19215            let soft_wrap = match self.soft_wrap_mode(cx) {
19216                SoftWrap::GitDiff => return,
19217                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19218                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19219                    language_settings::SoftWrap::None
19220                }
19221            };
19222            self.soft_wrap_mode_override = Some(soft_wrap);
19223        }
19224        cx.notify();
19225    }
19226
19227    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19228        let Some(workspace) = self.workspace() else {
19229            return;
19230        };
19231        let fs = workspace.read(cx).app_state().fs.clone();
19232        let current_show = TabBarSettings::get_global(cx).show;
19233        update_settings_file(fs, cx, move |setting, _| {
19234            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19235        });
19236    }
19237
19238    pub fn toggle_indent_guides(
19239        &mut self,
19240        _: &ToggleIndentGuides,
19241        _: &mut Window,
19242        cx: &mut Context<Self>,
19243    ) {
19244        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19245            self.buffer
19246                .read(cx)
19247                .language_settings(cx)
19248                .indent_guides
19249                .enabled
19250        });
19251        self.show_indent_guides = Some(!currently_enabled);
19252        cx.notify();
19253    }
19254
19255    fn should_show_indent_guides(&self) -> Option<bool> {
19256        self.show_indent_guides
19257    }
19258
19259    pub fn toggle_line_numbers(
19260        &mut self,
19261        _: &ToggleLineNumbers,
19262        _: &mut Window,
19263        cx: &mut Context<Self>,
19264    ) {
19265        let mut editor_settings = EditorSettings::get_global(cx).clone();
19266        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19267        EditorSettings::override_global(editor_settings, cx);
19268    }
19269
19270    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19271        if let Some(show_line_numbers) = self.show_line_numbers {
19272            return show_line_numbers;
19273        }
19274        EditorSettings::get_global(cx).gutter.line_numbers
19275    }
19276
19277    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19278        self.use_relative_line_numbers
19279            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19280    }
19281
19282    pub fn toggle_relative_line_numbers(
19283        &mut self,
19284        _: &ToggleRelativeLineNumbers,
19285        _: &mut Window,
19286        cx: &mut Context<Self>,
19287    ) {
19288        let is_relative = self.should_use_relative_line_numbers(cx);
19289        self.set_relative_line_number(Some(!is_relative), cx)
19290    }
19291
19292    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19293        self.use_relative_line_numbers = is_relative;
19294        cx.notify();
19295    }
19296
19297    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19298        self.show_gutter = show_gutter;
19299        cx.notify();
19300    }
19301
19302    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19303        self.show_scrollbars = ScrollbarAxes {
19304            horizontal: show,
19305            vertical: show,
19306        };
19307        cx.notify();
19308    }
19309
19310    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19311        self.show_scrollbars.vertical = show;
19312        cx.notify();
19313    }
19314
19315    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19316        self.show_scrollbars.horizontal = show;
19317        cx.notify();
19318    }
19319
19320    pub fn set_minimap_visibility(
19321        &mut self,
19322        minimap_visibility: MinimapVisibility,
19323        window: &mut Window,
19324        cx: &mut Context<Self>,
19325    ) {
19326        if self.minimap_visibility != minimap_visibility {
19327            if minimap_visibility.visible() && self.minimap.is_none() {
19328                let minimap_settings = EditorSettings::get_global(cx).minimap;
19329                self.minimap =
19330                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19331            }
19332            self.minimap_visibility = minimap_visibility;
19333            cx.notify();
19334        }
19335    }
19336
19337    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19338        self.set_show_scrollbars(false, cx);
19339        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19340    }
19341
19342    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19343        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19344    }
19345
19346    /// Normally the text in full mode and auto height editors is padded on the
19347    /// left side by roughly half a character width for improved hit testing.
19348    ///
19349    /// Use this method to disable this for cases where this is not wanted (e.g.
19350    /// if you want to align the editor text with some other text above or below)
19351    /// or if you want to add this padding to single-line editors.
19352    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19353        self.offset_content = offset_content;
19354        cx.notify();
19355    }
19356
19357    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19358        self.show_line_numbers = Some(show_line_numbers);
19359        cx.notify();
19360    }
19361
19362    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19363        self.disable_expand_excerpt_buttons = true;
19364        cx.notify();
19365    }
19366
19367    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19368        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19369        cx.notify();
19370    }
19371
19372    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19373        self.show_code_actions = Some(show_code_actions);
19374        cx.notify();
19375    }
19376
19377    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19378        self.show_runnables = Some(show_runnables);
19379        cx.notify();
19380    }
19381
19382    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19383        self.show_breakpoints = Some(show_breakpoints);
19384        cx.notify();
19385    }
19386
19387    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19388        if self.display_map.read(cx).masked != masked {
19389            self.display_map.update(cx, |map, _| map.masked = masked);
19390        }
19391        cx.notify()
19392    }
19393
19394    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19395        self.show_wrap_guides = Some(show_wrap_guides);
19396        cx.notify();
19397    }
19398
19399    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19400        self.show_indent_guides = Some(show_indent_guides);
19401        cx.notify();
19402    }
19403
19404    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19405        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19406            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19407                && let Some(dir) = file.abs_path(cx).parent()
19408            {
19409                return Some(dir.to_owned());
19410            }
19411        }
19412
19413        None
19414    }
19415
19416    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19417        self.active_excerpt(cx)?
19418            .1
19419            .read(cx)
19420            .file()
19421            .and_then(|f| f.as_local())
19422    }
19423
19424    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19425        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19426            let buffer = buffer.read(cx);
19427            if let Some(project_path) = buffer.project_path(cx) {
19428                let project = self.project()?.read(cx);
19429                project.absolute_path(&project_path, cx)
19430            } else {
19431                buffer
19432                    .file()
19433                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19434            }
19435        })
19436    }
19437
19438    pub fn reveal_in_finder(
19439        &mut self,
19440        _: &RevealInFileManager,
19441        _window: &mut Window,
19442        cx: &mut Context<Self>,
19443    ) {
19444        if let Some(target) = self.target_file(cx) {
19445            cx.reveal_path(&target.abs_path(cx));
19446        }
19447    }
19448
19449    pub fn copy_path(
19450        &mut self,
19451        _: &zed_actions::workspace::CopyPath,
19452        _window: &mut Window,
19453        cx: &mut Context<Self>,
19454    ) {
19455        if let Some(path) = self.target_file_abs_path(cx)
19456            && let Some(path) = path.to_str()
19457        {
19458            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19459        } else {
19460            cx.propagate();
19461        }
19462    }
19463
19464    pub fn copy_relative_path(
19465        &mut self,
19466        _: &zed_actions::workspace::CopyRelativePath,
19467        _window: &mut Window,
19468        cx: &mut Context<Self>,
19469    ) {
19470        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19471            let project = self.project()?.read(cx);
19472            let path = buffer.read(cx).file()?.path();
19473            let path = path.display(project.path_style(cx));
19474            Some(path)
19475        }) {
19476            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19477        } else {
19478            cx.propagate();
19479        }
19480    }
19481
19482    /// Returns the project path for the editor's buffer, if any buffer is
19483    /// opened in the editor.
19484    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19485        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19486            buffer.read(cx).project_path(cx)
19487        } else {
19488            None
19489        }
19490    }
19491
19492    // Returns true if the editor handled a go-to-line request
19493    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19494        maybe!({
19495            let breakpoint_store = self.breakpoint_store.as_ref()?;
19496
19497            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19498            else {
19499                self.clear_row_highlights::<ActiveDebugLine>();
19500                return None;
19501            };
19502
19503            let position = active_stack_frame.position;
19504            let buffer_id = position.buffer_id?;
19505            let snapshot = self
19506                .project
19507                .as_ref()?
19508                .read(cx)
19509                .buffer_for_id(buffer_id, cx)?
19510                .read(cx)
19511                .snapshot();
19512
19513            let mut handled = false;
19514            for (id, ExcerptRange { context, .. }) in
19515                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19516            {
19517                if context.start.cmp(&position, &snapshot).is_ge()
19518                    || context.end.cmp(&position, &snapshot).is_lt()
19519                {
19520                    continue;
19521                }
19522                let snapshot = self.buffer.read(cx).snapshot(cx);
19523                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19524
19525                handled = true;
19526                self.clear_row_highlights::<ActiveDebugLine>();
19527
19528                self.go_to_line::<ActiveDebugLine>(
19529                    multibuffer_anchor,
19530                    Some(cx.theme().colors().editor_debugger_active_line_background),
19531                    window,
19532                    cx,
19533                );
19534
19535                cx.notify();
19536            }
19537
19538            handled.then_some(())
19539        })
19540        .is_some()
19541    }
19542
19543    pub fn copy_file_name_without_extension(
19544        &mut self,
19545        _: &CopyFileNameWithoutExtension,
19546        _: &mut Window,
19547        cx: &mut Context<Self>,
19548    ) {
19549        if let Some(file) = self.target_file(cx)
19550            && let Some(file_stem) = file.path().file_stem()
19551        {
19552            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19553        }
19554    }
19555
19556    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19557        if let Some(file) = self.target_file(cx)
19558            && let Some(name) = file.path().file_name()
19559        {
19560            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19561        }
19562    }
19563
19564    pub fn toggle_git_blame(
19565        &mut self,
19566        _: &::git::Blame,
19567        window: &mut Window,
19568        cx: &mut Context<Self>,
19569    ) {
19570        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19571
19572        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19573            self.start_git_blame(true, window, cx);
19574        }
19575
19576        cx.notify();
19577    }
19578
19579    pub fn toggle_git_blame_inline(
19580        &mut self,
19581        _: &ToggleGitBlameInline,
19582        window: &mut Window,
19583        cx: &mut Context<Self>,
19584    ) {
19585        self.toggle_git_blame_inline_internal(true, window, cx);
19586        cx.notify();
19587    }
19588
19589    pub fn open_git_blame_commit(
19590        &mut self,
19591        _: &OpenGitBlameCommit,
19592        window: &mut Window,
19593        cx: &mut Context<Self>,
19594    ) {
19595        self.open_git_blame_commit_internal(window, cx);
19596    }
19597
19598    fn open_git_blame_commit_internal(
19599        &mut self,
19600        window: &mut Window,
19601        cx: &mut Context<Self>,
19602    ) -> Option<()> {
19603        let blame = self.blame.as_ref()?;
19604        let snapshot = self.snapshot(window, cx);
19605        let cursor = self.selections.newest::<Point>(cx).head();
19606        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19607        let (_, blame_entry) = blame
19608            .update(cx, |blame, cx| {
19609                blame
19610                    .blame_for_rows(
19611                        &[RowInfo {
19612                            buffer_id: Some(buffer.remote_id()),
19613                            buffer_row: Some(point.row),
19614                            ..Default::default()
19615                        }],
19616                        cx,
19617                    )
19618                    .next()
19619            })
19620            .flatten()?;
19621        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19622        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19623        let workspace = self.workspace()?.downgrade();
19624        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19625        None
19626    }
19627
19628    pub fn git_blame_inline_enabled(&self) -> bool {
19629        self.git_blame_inline_enabled
19630    }
19631
19632    pub fn toggle_selection_menu(
19633        &mut self,
19634        _: &ToggleSelectionMenu,
19635        _: &mut Window,
19636        cx: &mut Context<Self>,
19637    ) {
19638        self.show_selection_menu = self
19639            .show_selection_menu
19640            .map(|show_selections_menu| !show_selections_menu)
19641            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19642
19643        cx.notify();
19644    }
19645
19646    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19647        self.show_selection_menu
19648            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19649    }
19650
19651    fn start_git_blame(
19652        &mut self,
19653        user_triggered: bool,
19654        window: &mut Window,
19655        cx: &mut Context<Self>,
19656    ) {
19657        if let Some(project) = self.project() {
19658            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19659                && buffer.read(cx).file().is_none()
19660            {
19661                return;
19662            }
19663
19664            let focused = self.focus_handle(cx).contains_focused(window, cx);
19665
19666            let project = project.clone();
19667            let blame = cx
19668                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19669            self.blame_subscription =
19670                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19671            self.blame = Some(blame);
19672        }
19673    }
19674
19675    fn toggle_git_blame_inline_internal(
19676        &mut self,
19677        user_triggered: bool,
19678        window: &mut Window,
19679        cx: &mut Context<Self>,
19680    ) {
19681        if self.git_blame_inline_enabled {
19682            self.git_blame_inline_enabled = false;
19683            self.show_git_blame_inline = false;
19684            self.show_git_blame_inline_delay_task.take();
19685        } else {
19686            self.git_blame_inline_enabled = true;
19687            self.start_git_blame_inline(user_triggered, window, cx);
19688        }
19689
19690        cx.notify();
19691    }
19692
19693    fn start_git_blame_inline(
19694        &mut self,
19695        user_triggered: bool,
19696        window: &mut Window,
19697        cx: &mut Context<Self>,
19698    ) {
19699        self.start_git_blame(user_triggered, window, cx);
19700
19701        if ProjectSettings::get_global(cx)
19702            .git
19703            .inline_blame_delay()
19704            .is_some()
19705        {
19706            self.start_inline_blame_timer(window, cx);
19707        } else {
19708            self.show_git_blame_inline = true
19709        }
19710    }
19711
19712    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19713        self.blame.as_ref()
19714    }
19715
19716    pub fn show_git_blame_gutter(&self) -> bool {
19717        self.show_git_blame_gutter
19718    }
19719
19720    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19721        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19722    }
19723
19724    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19725        self.show_git_blame_inline
19726            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19727            && !self.newest_selection_head_on_empty_line(cx)
19728            && self.has_blame_entries(cx)
19729    }
19730
19731    fn has_blame_entries(&self, cx: &App) -> bool {
19732        self.blame()
19733            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19734    }
19735
19736    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19737        let cursor_anchor = self.selections.newest_anchor().head();
19738
19739        let snapshot = self.buffer.read(cx).snapshot(cx);
19740        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19741
19742        snapshot.line_len(buffer_row) == 0
19743    }
19744
19745    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19746        let buffer_and_selection = maybe!({
19747            let selection = self.selections.newest::<Point>(cx);
19748            let selection_range = selection.range();
19749
19750            let multi_buffer = self.buffer().read(cx);
19751            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19752            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19753
19754            let (buffer, range, _) = if selection.reversed {
19755                buffer_ranges.first()
19756            } else {
19757                buffer_ranges.last()
19758            }?;
19759
19760            let selection = text::ToPoint::to_point(&range.start, buffer).row
19761                ..text::ToPoint::to_point(&range.end, buffer).row;
19762            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19763        });
19764
19765        let Some((buffer, selection)) = buffer_and_selection else {
19766            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19767        };
19768
19769        let Some(project) = self.project() else {
19770            return Task::ready(Err(anyhow!("editor does not have project")));
19771        };
19772
19773        project.update(cx, |project, cx| {
19774            project.get_permalink_to_line(&buffer, selection, cx)
19775        })
19776    }
19777
19778    pub fn copy_permalink_to_line(
19779        &mut self,
19780        _: &CopyPermalinkToLine,
19781        window: &mut Window,
19782        cx: &mut Context<Self>,
19783    ) {
19784        let permalink_task = self.get_permalink_to_line(cx);
19785        let workspace = self.workspace();
19786
19787        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19788            Ok(permalink) => {
19789                cx.update(|_, cx| {
19790                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19791                })
19792                .ok();
19793            }
19794            Err(err) => {
19795                let message = format!("Failed to copy permalink: {err}");
19796
19797                anyhow::Result::<()>::Err(err).log_err();
19798
19799                if let Some(workspace) = workspace {
19800                    workspace
19801                        .update_in(cx, |workspace, _, cx| {
19802                            struct CopyPermalinkToLine;
19803
19804                            workspace.show_toast(
19805                                Toast::new(
19806                                    NotificationId::unique::<CopyPermalinkToLine>(),
19807                                    message,
19808                                ),
19809                                cx,
19810                            )
19811                        })
19812                        .ok();
19813                }
19814            }
19815        })
19816        .detach();
19817    }
19818
19819    pub fn copy_file_location(
19820        &mut self,
19821        _: &CopyFileLocation,
19822        _: &mut Window,
19823        cx: &mut Context<Self>,
19824    ) {
19825        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19826        if let Some(file) = self.target_file(cx) {
19827            let path = file.path().display(file.path_style(cx));
19828            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19829        }
19830    }
19831
19832    pub fn open_permalink_to_line(
19833        &mut self,
19834        _: &OpenPermalinkToLine,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        let permalink_task = self.get_permalink_to_line(cx);
19839        let workspace = self.workspace();
19840
19841        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19842            Ok(permalink) => {
19843                cx.update(|_, cx| {
19844                    cx.open_url(permalink.as_ref());
19845                })
19846                .ok();
19847            }
19848            Err(err) => {
19849                let message = format!("Failed to open permalink: {err}");
19850
19851                anyhow::Result::<()>::Err(err).log_err();
19852
19853                if let Some(workspace) = workspace {
19854                    workspace
19855                        .update(cx, |workspace, cx| {
19856                            struct OpenPermalinkToLine;
19857
19858                            workspace.show_toast(
19859                                Toast::new(
19860                                    NotificationId::unique::<OpenPermalinkToLine>(),
19861                                    message,
19862                                ),
19863                                cx,
19864                            )
19865                        })
19866                        .ok();
19867                }
19868            }
19869        })
19870        .detach();
19871    }
19872
19873    pub fn insert_uuid_v4(
19874        &mut self,
19875        _: &InsertUuidV4,
19876        window: &mut Window,
19877        cx: &mut Context<Self>,
19878    ) {
19879        self.insert_uuid(UuidVersion::V4, window, cx);
19880    }
19881
19882    pub fn insert_uuid_v7(
19883        &mut self,
19884        _: &InsertUuidV7,
19885        window: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) {
19888        self.insert_uuid(UuidVersion::V7, window, cx);
19889    }
19890
19891    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19892        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19893        self.transact(window, cx, |this, window, cx| {
19894            let edits = this
19895                .selections
19896                .all::<Point>(cx)
19897                .into_iter()
19898                .map(|selection| {
19899                    let uuid = match version {
19900                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19901                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19902                    };
19903
19904                    (selection.range(), uuid.to_string())
19905                });
19906            this.edit(edits, cx);
19907            this.refresh_edit_prediction(true, false, window, cx);
19908        });
19909    }
19910
19911    pub fn open_selections_in_multibuffer(
19912        &mut self,
19913        _: &OpenSelectionsInMultibuffer,
19914        window: &mut Window,
19915        cx: &mut Context<Self>,
19916    ) {
19917        let multibuffer = self.buffer.read(cx);
19918
19919        let Some(buffer) = multibuffer.as_singleton() else {
19920            return;
19921        };
19922
19923        let Some(workspace) = self.workspace() else {
19924            return;
19925        };
19926
19927        let title = multibuffer.title(cx).to_string();
19928
19929        let locations = self
19930            .selections
19931            .all_anchors(cx)
19932            .iter()
19933            .map(|selection| {
19934                (
19935                    buffer.clone(),
19936                    (selection.start.text_anchor..selection.end.text_anchor)
19937                        .to_point(buffer.read(cx)),
19938                )
19939            })
19940            .into_group_map();
19941
19942        cx.spawn_in(window, async move |_, cx| {
19943            workspace.update_in(cx, |workspace, window, cx| {
19944                Self::open_locations_in_multibuffer(
19945                    workspace,
19946                    locations,
19947                    format!("Selections for '{title}'"),
19948                    false,
19949                    MultibufferSelectionMode::All,
19950                    window,
19951                    cx,
19952                );
19953            })
19954        })
19955        .detach();
19956    }
19957
19958    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19959    /// last highlight added will be used.
19960    ///
19961    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19962    pub fn highlight_rows<T: 'static>(
19963        &mut self,
19964        range: Range<Anchor>,
19965        color: Hsla,
19966        options: RowHighlightOptions,
19967        cx: &mut Context<Self>,
19968    ) {
19969        let snapshot = self.buffer().read(cx).snapshot(cx);
19970        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19971        let ix = row_highlights.binary_search_by(|highlight| {
19972            Ordering::Equal
19973                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19974                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19975        });
19976
19977        if let Err(mut ix) = ix {
19978            let index = post_inc(&mut self.highlight_order);
19979
19980            // If this range intersects with the preceding highlight, then merge it with
19981            // the preceding highlight. Otherwise insert a new highlight.
19982            let mut merged = false;
19983            if ix > 0 {
19984                let prev_highlight = &mut row_highlights[ix - 1];
19985                if prev_highlight
19986                    .range
19987                    .end
19988                    .cmp(&range.start, &snapshot)
19989                    .is_ge()
19990                {
19991                    ix -= 1;
19992                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19993                        prev_highlight.range.end = range.end;
19994                    }
19995                    merged = true;
19996                    prev_highlight.index = index;
19997                    prev_highlight.color = color;
19998                    prev_highlight.options = options;
19999                }
20000            }
20001
20002            if !merged {
20003                row_highlights.insert(
20004                    ix,
20005                    RowHighlight {
20006                        range,
20007                        index,
20008                        color,
20009                        options,
20010                        type_id: TypeId::of::<T>(),
20011                    },
20012                );
20013            }
20014
20015            // If any of the following highlights intersect with this one, merge them.
20016            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20017                let highlight = &row_highlights[ix];
20018                if next_highlight
20019                    .range
20020                    .start
20021                    .cmp(&highlight.range.end, &snapshot)
20022                    .is_le()
20023                {
20024                    if next_highlight
20025                        .range
20026                        .end
20027                        .cmp(&highlight.range.end, &snapshot)
20028                        .is_gt()
20029                    {
20030                        row_highlights[ix].range.end = next_highlight.range.end;
20031                    }
20032                    row_highlights.remove(ix + 1);
20033                } else {
20034                    break;
20035                }
20036            }
20037        }
20038    }
20039
20040    /// Remove any highlighted row ranges of the given type that intersect the
20041    /// given ranges.
20042    pub fn remove_highlighted_rows<T: 'static>(
20043        &mut self,
20044        ranges_to_remove: Vec<Range<Anchor>>,
20045        cx: &mut Context<Self>,
20046    ) {
20047        let snapshot = self.buffer().read(cx).snapshot(cx);
20048        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20049        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20050        row_highlights.retain(|highlight| {
20051            while let Some(range_to_remove) = ranges_to_remove.peek() {
20052                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20053                    Ordering::Less | Ordering::Equal => {
20054                        ranges_to_remove.next();
20055                    }
20056                    Ordering::Greater => {
20057                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20058                            Ordering::Less | Ordering::Equal => {
20059                                return false;
20060                            }
20061                            Ordering::Greater => break,
20062                        }
20063                    }
20064                }
20065            }
20066
20067            true
20068        })
20069    }
20070
20071    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20072    pub fn clear_row_highlights<T: 'static>(&mut self) {
20073        self.highlighted_rows.remove(&TypeId::of::<T>());
20074    }
20075
20076    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20077    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20078        self.highlighted_rows
20079            .get(&TypeId::of::<T>())
20080            .map_or(&[] as &[_], |vec| vec.as_slice())
20081            .iter()
20082            .map(|highlight| (highlight.range.clone(), highlight.color))
20083    }
20084
20085    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20086    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20087    /// Allows to ignore certain kinds of highlights.
20088    pub fn highlighted_display_rows(
20089        &self,
20090        window: &mut Window,
20091        cx: &mut App,
20092    ) -> BTreeMap<DisplayRow, LineHighlight> {
20093        let snapshot = self.snapshot(window, cx);
20094        let mut used_highlight_orders = HashMap::default();
20095        self.highlighted_rows
20096            .iter()
20097            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20098            .fold(
20099                BTreeMap::<DisplayRow, LineHighlight>::new(),
20100                |mut unique_rows, highlight| {
20101                    let start = highlight.range.start.to_display_point(&snapshot);
20102                    let end = highlight.range.end.to_display_point(&snapshot);
20103                    let start_row = start.row().0;
20104                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20105                        && end.column() == 0
20106                    {
20107                        end.row().0.saturating_sub(1)
20108                    } else {
20109                        end.row().0
20110                    };
20111                    for row in start_row..=end_row {
20112                        let used_index =
20113                            used_highlight_orders.entry(row).or_insert(highlight.index);
20114                        if highlight.index >= *used_index {
20115                            *used_index = highlight.index;
20116                            unique_rows.insert(
20117                                DisplayRow(row),
20118                                LineHighlight {
20119                                    include_gutter: highlight.options.include_gutter,
20120                                    border: None,
20121                                    background: highlight.color.into(),
20122                                    type_id: Some(highlight.type_id),
20123                                },
20124                            );
20125                        }
20126                    }
20127                    unique_rows
20128                },
20129            )
20130    }
20131
20132    pub fn highlighted_display_row_for_autoscroll(
20133        &self,
20134        snapshot: &DisplaySnapshot,
20135    ) -> Option<DisplayRow> {
20136        self.highlighted_rows
20137            .values()
20138            .flat_map(|highlighted_rows| highlighted_rows.iter())
20139            .filter_map(|highlight| {
20140                if highlight.options.autoscroll {
20141                    Some(highlight.range.start.to_display_point(snapshot).row())
20142                } else {
20143                    None
20144                }
20145            })
20146            .min()
20147    }
20148
20149    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20150        self.highlight_background::<SearchWithinRange>(
20151            ranges,
20152            |colors| colors.colors().editor_document_highlight_read_background,
20153            cx,
20154        )
20155    }
20156
20157    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20158        self.breadcrumb_header = Some(new_header);
20159    }
20160
20161    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20162        self.clear_background_highlights::<SearchWithinRange>(cx);
20163    }
20164
20165    pub fn highlight_background<T: 'static>(
20166        &mut self,
20167        ranges: &[Range<Anchor>],
20168        color_fetcher: fn(&Theme) -> Hsla,
20169        cx: &mut Context<Self>,
20170    ) {
20171        self.background_highlights.insert(
20172            HighlightKey::Type(TypeId::of::<T>()),
20173            (color_fetcher, Arc::from(ranges)),
20174        );
20175        self.scrollbar_marker_state.dirty = true;
20176        cx.notify();
20177    }
20178
20179    pub fn highlight_background_key<T: 'static>(
20180        &mut self,
20181        key: usize,
20182        ranges: &[Range<Anchor>],
20183        color_fetcher: fn(&Theme) -> Hsla,
20184        cx: &mut Context<Self>,
20185    ) {
20186        self.background_highlights.insert(
20187            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20188            (color_fetcher, Arc::from(ranges)),
20189        );
20190        self.scrollbar_marker_state.dirty = true;
20191        cx.notify();
20192    }
20193
20194    pub fn clear_background_highlights<T: 'static>(
20195        &mut self,
20196        cx: &mut Context<Self>,
20197    ) -> Option<BackgroundHighlight> {
20198        let text_highlights = self
20199            .background_highlights
20200            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20201        if !text_highlights.1.is_empty() {
20202            self.scrollbar_marker_state.dirty = true;
20203            cx.notify();
20204        }
20205        Some(text_highlights)
20206    }
20207
20208    pub fn highlight_gutter<T: 'static>(
20209        &mut self,
20210        ranges: impl Into<Vec<Range<Anchor>>>,
20211        color_fetcher: fn(&App) -> Hsla,
20212        cx: &mut Context<Self>,
20213    ) {
20214        self.gutter_highlights
20215            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20216        cx.notify();
20217    }
20218
20219    pub fn clear_gutter_highlights<T: 'static>(
20220        &mut self,
20221        cx: &mut Context<Self>,
20222    ) -> Option<GutterHighlight> {
20223        cx.notify();
20224        self.gutter_highlights.remove(&TypeId::of::<T>())
20225    }
20226
20227    pub fn insert_gutter_highlight<T: 'static>(
20228        &mut self,
20229        range: Range<Anchor>,
20230        color_fetcher: fn(&App) -> Hsla,
20231        cx: &mut Context<Self>,
20232    ) {
20233        let snapshot = self.buffer().read(cx).snapshot(cx);
20234        let mut highlights = self
20235            .gutter_highlights
20236            .remove(&TypeId::of::<T>())
20237            .map(|(_, highlights)| highlights)
20238            .unwrap_or_default();
20239        let ix = highlights.binary_search_by(|highlight| {
20240            Ordering::Equal
20241                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20242                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20243        });
20244        if let Err(ix) = ix {
20245            highlights.insert(ix, range);
20246        }
20247        self.gutter_highlights
20248            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20249    }
20250
20251    pub fn remove_gutter_highlights<T: 'static>(
20252        &mut self,
20253        ranges_to_remove: Vec<Range<Anchor>>,
20254        cx: &mut Context<Self>,
20255    ) {
20256        let snapshot = self.buffer().read(cx).snapshot(cx);
20257        let Some((color_fetcher, mut gutter_highlights)) =
20258            self.gutter_highlights.remove(&TypeId::of::<T>())
20259        else {
20260            return;
20261        };
20262        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20263        gutter_highlights.retain(|highlight| {
20264            while let Some(range_to_remove) = ranges_to_remove.peek() {
20265                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20266                    Ordering::Less | Ordering::Equal => {
20267                        ranges_to_remove.next();
20268                    }
20269                    Ordering::Greater => {
20270                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20271                            Ordering::Less | Ordering::Equal => {
20272                                return false;
20273                            }
20274                            Ordering::Greater => break,
20275                        }
20276                    }
20277                }
20278            }
20279
20280            true
20281        });
20282        self.gutter_highlights
20283            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20284    }
20285
20286    #[cfg(feature = "test-support")]
20287    pub fn all_text_highlights(
20288        &self,
20289        window: &mut Window,
20290        cx: &mut Context<Self>,
20291    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20292        let snapshot = self.snapshot(window, cx);
20293        self.display_map.update(cx, |display_map, _| {
20294            display_map
20295                .all_text_highlights()
20296                .map(|highlight| {
20297                    let (style, ranges) = highlight.as_ref();
20298                    (
20299                        *style,
20300                        ranges
20301                            .iter()
20302                            .map(|range| range.clone().to_display_points(&snapshot))
20303                            .collect(),
20304                    )
20305                })
20306                .collect()
20307        })
20308    }
20309
20310    #[cfg(feature = "test-support")]
20311    pub fn all_text_background_highlights(
20312        &self,
20313        window: &mut Window,
20314        cx: &mut Context<Self>,
20315    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20316        let snapshot = self.snapshot(window, cx);
20317        let buffer = &snapshot.buffer_snapshot();
20318        let start = buffer.anchor_before(0);
20319        let end = buffer.anchor_after(buffer.len());
20320        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20321    }
20322
20323    #[cfg(any(test, feature = "test-support"))]
20324    pub fn sorted_background_highlights_in_range(
20325        &self,
20326        search_range: Range<Anchor>,
20327        display_snapshot: &DisplaySnapshot,
20328        theme: &Theme,
20329    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20330        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20331        res.sort_by(|a, b| {
20332            a.0.start
20333                .cmp(&b.0.start)
20334                .then_with(|| a.0.end.cmp(&b.0.end))
20335                .then_with(|| a.1.cmp(&b.1))
20336        });
20337        res
20338    }
20339
20340    #[cfg(feature = "test-support")]
20341    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20342        let snapshot = self.buffer().read(cx).snapshot(cx);
20343
20344        let highlights = self
20345            .background_highlights
20346            .get(&HighlightKey::Type(TypeId::of::<
20347                items::BufferSearchHighlights,
20348            >()));
20349
20350        if let Some((_color, ranges)) = highlights {
20351            ranges
20352                .iter()
20353                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20354                .collect_vec()
20355        } else {
20356            vec![]
20357        }
20358    }
20359
20360    fn document_highlights_for_position<'a>(
20361        &'a self,
20362        position: Anchor,
20363        buffer: &'a MultiBufferSnapshot,
20364    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20365        let read_highlights = self
20366            .background_highlights
20367            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20368            .map(|h| &h.1);
20369        let write_highlights = self
20370            .background_highlights
20371            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20372            .map(|h| &h.1);
20373        let left_position = position.bias_left(buffer);
20374        let right_position = position.bias_right(buffer);
20375        read_highlights
20376            .into_iter()
20377            .chain(write_highlights)
20378            .flat_map(move |ranges| {
20379                let start_ix = match ranges.binary_search_by(|probe| {
20380                    let cmp = probe.end.cmp(&left_position, buffer);
20381                    if cmp.is_ge() {
20382                        Ordering::Greater
20383                    } else {
20384                        Ordering::Less
20385                    }
20386                }) {
20387                    Ok(i) | Err(i) => i,
20388                };
20389
20390                ranges[start_ix..]
20391                    .iter()
20392                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20393            })
20394    }
20395
20396    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20397        self.background_highlights
20398            .get(&HighlightKey::Type(TypeId::of::<T>()))
20399            .is_some_and(|(_, highlights)| !highlights.is_empty())
20400    }
20401
20402    /// Returns all background highlights for a given range.
20403    ///
20404    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20405    pub fn background_highlights_in_range(
20406        &self,
20407        search_range: Range<Anchor>,
20408        display_snapshot: &DisplaySnapshot,
20409        theme: &Theme,
20410    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20411        let mut results = Vec::new();
20412        for (color_fetcher, ranges) in self.background_highlights.values() {
20413            let color = color_fetcher(theme);
20414            let start_ix = match ranges.binary_search_by(|probe| {
20415                let cmp = probe
20416                    .end
20417                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20418                if cmp.is_gt() {
20419                    Ordering::Greater
20420                } else {
20421                    Ordering::Less
20422                }
20423            }) {
20424                Ok(i) | Err(i) => i,
20425            };
20426            for range in &ranges[start_ix..] {
20427                if range
20428                    .start
20429                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20430                    .is_ge()
20431                {
20432                    break;
20433                }
20434
20435                let start = range.start.to_display_point(display_snapshot);
20436                let end = range.end.to_display_point(display_snapshot);
20437                results.push((start..end, color))
20438            }
20439        }
20440        results
20441    }
20442
20443    pub fn gutter_highlights_in_range(
20444        &self,
20445        search_range: Range<Anchor>,
20446        display_snapshot: &DisplaySnapshot,
20447        cx: &App,
20448    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20449        let mut results = Vec::new();
20450        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20451            let color = color_fetcher(cx);
20452            let start_ix = match ranges.binary_search_by(|probe| {
20453                let cmp = probe
20454                    .end
20455                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20456                if cmp.is_gt() {
20457                    Ordering::Greater
20458                } else {
20459                    Ordering::Less
20460                }
20461            }) {
20462                Ok(i) | Err(i) => i,
20463            };
20464            for range in &ranges[start_ix..] {
20465                if range
20466                    .start
20467                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20468                    .is_ge()
20469                {
20470                    break;
20471                }
20472
20473                let start = range.start.to_display_point(display_snapshot);
20474                let end = range.end.to_display_point(display_snapshot);
20475                results.push((start..end, color))
20476            }
20477        }
20478        results
20479    }
20480
20481    /// Get the text ranges corresponding to the redaction query
20482    pub fn redacted_ranges(
20483        &self,
20484        search_range: Range<Anchor>,
20485        display_snapshot: &DisplaySnapshot,
20486        cx: &App,
20487    ) -> Vec<Range<DisplayPoint>> {
20488        display_snapshot
20489            .buffer_snapshot()
20490            .redacted_ranges(search_range, |file| {
20491                if let Some(file) = file {
20492                    file.is_private()
20493                        && EditorSettings::get(
20494                            Some(SettingsLocation {
20495                                worktree_id: file.worktree_id(cx),
20496                                path: file.path().as_ref(),
20497                            }),
20498                            cx,
20499                        )
20500                        .redact_private_values
20501                } else {
20502                    false
20503                }
20504            })
20505            .map(|range| {
20506                range.start.to_display_point(display_snapshot)
20507                    ..range.end.to_display_point(display_snapshot)
20508            })
20509            .collect()
20510    }
20511
20512    pub fn highlight_text_key<T: 'static>(
20513        &mut self,
20514        key: usize,
20515        ranges: Vec<Range<Anchor>>,
20516        style: HighlightStyle,
20517        cx: &mut Context<Self>,
20518    ) {
20519        self.display_map.update(cx, |map, _| {
20520            map.highlight_text(
20521                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20522                ranges,
20523                style,
20524            );
20525        });
20526        cx.notify();
20527    }
20528
20529    pub fn highlight_text<T: 'static>(
20530        &mut self,
20531        ranges: Vec<Range<Anchor>>,
20532        style: HighlightStyle,
20533        cx: &mut Context<Self>,
20534    ) {
20535        self.display_map.update(cx, |map, _| {
20536            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20537        });
20538        cx.notify();
20539    }
20540
20541    pub(crate) fn highlight_inlays<T: 'static>(
20542        &mut self,
20543        highlights: Vec<InlayHighlight>,
20544        style: HighlightStyle,
20545        cx: &mut Context<Self>,
20546    ) {
20547        self.display_map.update(cx, |map, _| {
20548            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20549        });
20550        cx.notify();
20551    }
20552
20553    pub fn text_highlights<'a, T: 'static>(
20554        &'a self,
20555        cx: &'a App,
20556    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20557        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20558    }
20559
20560    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20561        let cleared = self
20562            .display_map
20563            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20564        if cleared {
20565            cx.notify();
20566        }
20567    }
20568
20569    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20570        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20571            && self.focus_handle.is_focused(window)
20572    }
20573
20574    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20575        self.show_cursor_when_unfocused = is_enabled;
20576        cx.notify();
20577    }
20578
20579    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20580        cx.notify();
20581    }
20582
20583    fn on_debug_session_event(
20584        &mut self,
20585        _session: Entity<Session>,
20586        event: &SessionEvent,
20587        cx: &mut Context<Self>,
20588    ) {
20589        if let SessionEvent::InvalidateInlineValue = event {
20590            self.refresh_inline_values(cx);
20591        }
20592    }
20593
20594    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20595        let Some(project) = self.project.clone() else {
20596            return;
20597        };
20598
20599        if !self.inline_value_cache.enabled {
20600            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20601            self.splice_inlays(&inlays, Vec::new(), cx);
20602            return;
20603        }
20604
20605        let current_execution_position = self
20606            .highlighted_rows
20607            .get(&TypeId::of::<ActiveDebugLine>())
20608            .and_then(|lines| lines.last().map(|line| line.range.end));
20609
20610        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20611            let inline_values = editor
20612                .update(cx, |editor, cx| {
20613                    let Some(current_execution_position) = current_execution_position else {
20614                        return Some(Task::ready(Ok(Vec::new())));
20615                    };
20616
20617                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20618                        let snapshot = buffer.snapshot(cx);
20619
20620                        let excerpt = snapshot.excerpt_containing(
20621                            current_execution_position..current_execution_position,
20622                        )?;
20623
20624                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20625                    })?;
20626
20627                    let range =
20628                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20629
20630                    project.inline_values(buffer, range, cx)
20631                })
20632                .ok()
20633                .flatten()?
20634                .await
20635                .context("refreshing debugger inlays")
20636                .log_err()?;
20637
20638            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20639
20640            for (buffer_id, inline_value) in inline_values
20641                .into_iter()
20642                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20643            {
20644                buffer_inline_values
20645                    .entry(buffer_id)
20646                    .or_default()
20647                    .push(inline_value);
20648            }
20649
20650            editor
20651                .update(cx, |editor, cx| {
20652                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20653                    let mut new_inlays = Vec::default();
20654
20655                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20656                        let buffer_id = buffer_snapshot.remote_id();
20657                        buffer_inline_values
20658                            .get(&buffer_id)
20659                            .into_iter()
20660                            .flatten()
20661                            .for_each(|hint| {
20662                                let inlay = Inlay::debugger(
20663                                    post_inc(&mut editor.next_inlay_id),
20664                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20665                                    hint.text(),
20666                                );
20667                                if !inlay.text().chars().contains(&'\n') {
20668                                    new_inlays.push(inlay);
20669                                }
20670                            });
20671                    }
20672
20673                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20674                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20675
20676                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20677                })
20678                .ok()?;
20679            Some(())
20680        });
20681    }
20682
20683    fn on_buffer_event(
20684        &mut self,
20685        multibuffer: &Entity<MultiBuffer>,
20686        event: &multi_buffer::Event,
20687        window: &mut Window,
20688        cx: &mut Context<Self>,
20689    ) {
20690        match event {
20691            multi_buffer::Event::Edited {
20692                singleton_buffer_edited,
20693                edited_buffer,
20694            } => {
20695                self.scrollbar_marker_state.dirty = true;
20696                self.active_indent_guides_state.dirty = true;
20697                self.refresh_active_diagnostics(cx);
20698                self.refresh_code_actions(window, cx);
20699                self.refresh_selected_text_highlights(true, window, cx);
20700                self.refresh_single_line_folds(window, cx);
20701                refresh_matching_bracket_highlights(self, window, cx);
20702                if self.has_active_edit_prediction() {
20703                    self.update_visible_edit_prediction(window, cx);
20704                }
20705                if let Some(project) = self.project.as_ref()
20706                    && let Some(edited_buffer) = edited_buffer
20707                {
20708                    project.update(cx, |project, cx| {
20709                        self.registered_buffers
20710                            .entry(edited_buffer.read(cx).remote_id())
20711                            .or_insert_with(|| {
20712                                project.register_buffer_with_language_servers(edited_buffer, cx)
20713                            });
20714                    });
20715                }
20716                cx.emit(EditorEvent::BufferEdited);
20717                cx.emit(SearchEvent::MatchesInvalidated);
20718
20719                if let Some(buffer) = edited_buffer {
20720                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20721                }
20722
20723                if *singleton_buffer_edited {
20724                    if let Some(buffer) = edited_buffer
20725                        && buffer.read(cx).file().is_none()
20726                    {
20727                        cx.emit(EditorEvent::TitleChanged);
20728                    }
20729                    if let Some(project) = &self.project {
20730                        #[allow(clippy::mutable_key_type)]
20731                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20732                            multibuffer
20733                                .all_buffers()
20734                                .into_iter()
20735                                .filter_map(|buffer| {
20736                                    buffer.update(cx, |buffer, cx| {
20737                                        let language = buffer.language()?;
20738                                        let should_discard = project.update(cx, |project, cx| {
20739                                            project.is_local()
20740                                                && !project.has_language_servers_for(buffer, cx)
20741                                        });
20742                                        should_discard.not().then_some(language.clone())
20743                                    })
20744                                })
20745                                .collect::<HashSet<_>>()
20746                        });
20747                        if !languages_affected.is_empty() {
20748                            self.refresh_inlay_hints(
20749                                InlayHintRefreshReason::BufferEdited(languages_affected),
20750                                cx,
20751                            );
20752                        }
20753                    }
20754                }
20755
20756                let Some(project) = &self.project else { return };
20757                let (telemetry, is_via_ssh) = {
20758                    let project = project.read(cx);
20759                    let telemetry = project.client().telemetry().clone();
20760                    let is_via_ssh = project.is_via_remote_server();
20761                    (telemetry, is_via_ssh)
20762                };
20763                refresh_linked_ranges(self, window, cx);
20764                telemetry.log_edit_event("editor", is_via_ssh);
20765            }
20766            multi_buffer::Event::ExcerptsAdded {
20767                buffer,
20768                predecessor,
20769                excerpts,
20770            } => {
20771                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20772                let buffer_id = buffer.read(cx).remote_id();
20773                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20774                    && let Some(project) = &self.project
20775                {
20776                    update_uncommitted_diff_for_buffer(
20777                        cx.entity(),
20778                        project,
20779                        [buffer.clone()],
20780                        self.buffer.clone(),
20781                        cx,
20782                    )
20783                    .detach();
20784                }
20785                if self.active_diagnostics != ActiveDiagnostic::All {
20786                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20787                }
20788                cx.emit(EditorEvent::ExcerptsAdded {
20789                    buffer: buffer.clone(),
20790                    predecessor: *predecessor,
20791                    excerpts: excerpts.clone(),
20792                });
20793                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20794            }
20795            multi_buffer::Event::ExcerptsRemoved {
20796                ids,
20797                removed_buffer_ids,
20798            } => {
20799                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20800                let buffer = self.buffer.read(cx);
20801                self.registered_buffers
20802                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20803                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20804                cx.emit(EditorEvent::ExcerptsRemoved {
20805                    ids: ids.clone(),
20806                    removed_buffer_ids: removed_buffer_ids.clone(),
20807                });
20808            }
20809            multi_buffer::Event::ExcerptsEdited {
20810                excerpt_ids,
20811                buffer_ids,
20812            } => {
20813                self.display_map.update(cx, |map, cx| {
20814                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20815                });
20816                cx.emit(EditorEvent::ExcerptsEdited {
20817                    ids: excerpt_ids.clone(),
20818                });
20819            }
20820            multi_buffer::Event::ExcerptsExpanded { ids } => {
20821                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20822                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20823            }
20824            multi_buffer::Event::Reparsed(buffer_id) => {
20825                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20826                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20827
20828                cx.emit(EditorEvent::Reparsed(*buffer_id));
20829            }
20830            multi_buffer::Event::DiffHunksToggled => {
20831                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20832            }
20833            multi_buffer::Event::LanguageChanged(buffer_id) => {
20834                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20835                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20836                cx.emit(EditorEvent::Reparsed(*buffer_id));
20837                cx.notify();
20838            }
20839            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20840            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20841            multi_buffer::Event::FileHandleChanged
20842            | multi_buffer::Event::Reloaded
20843            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20844            multi_buffer::Event::DiagnosticsUpdated => {
20845                self.update_diagnostics_state(window, cx);
20846            }
20847            _ => {}
20848        };
20849    }
20850
20851    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20852        if !self.diagnostics_enabled() {
20853            return;
20854        }
20855        self.refresh_active_diagnostics(cx);
20856        self.refresh_inline_diagnostics(true, window, cx);
20857        self.scrollbar_marker_state.dirty = true;
20858        cx.notify();
20859    }
20860
20861    pub fn start_temporary_diff_override(&mut self) {
20862        self.load_diff_task.take();
20863        self.temporary_diff_override = true;
20864    }
20865
20866    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20867        self.temporary_diff_override = false;
20868        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20869        self.buffer.update(cx, |buffer, cx| {
20870            buffer.set_all_diff_hunks_collapsed(cx);
20871        });
20872
20873        if let Some(project) = self.project.clone() {
20874            self.load_diff_task = Some(
20875                update_uncommitted_diff_for_buffer(
20876                    cx.entity(),
20877                    &project,
20878                    self.buffer.read(cx).all_buffers(),
20879                    self.buffer.clone(),
20880                    cx,
20881                )
20882                .shared(),
20883            );
20884        }
20885    }
20886
20887    fn on_display_map_changed(
20888        &mut self,
20889        _: Entity<DisplayMap>,
20890        _: &mut Window,
20891        cx: &mut Context<Self>,
20892    ) {
20893        cx.notify();
20894    }
20895
20896    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20897        if self.diagnostics_enabled() {
20898            let new_severity = EditorSettings::get_global(cx)
20899                .diagnostics_max_severity
20900                .unwrap_or(DiagnosticSeverity::Hint);
20901            self.set_max_diagnostics_severity(new_severity, cx);
20902        }
20903        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20904        self.update_edit_prediction_settings(cx);
20905        self.refresh_edit_prediction(true, false, window, cx);
20906        self.refresh_inline_values(cx);
20907        self.refresh_inlay_hints(
20908            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20909                self.selections.newest_anchor().head(),
20910                &self.buffer.read(cx).snapshot(cx),
20911                cx,
20912            )),
20913            cx,
20914        );
20915
20916        let old_cursor_shape = self.cursor_shape;
20917        let old_show_breadcrumbs = self.show_breadcrumbs;
20918
20919        {
20920            let editor_settings = EditorSettings::get_global(cx);
20921            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20922            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20923            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20924            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20925        }
20926
20927        if old_cursor_shape != self.cursor_shape {
20928            cx.emit(EditorEvent::CursorShapeChanged);
20929        }
20930
20931        if old_show_breadcrumbs != self.show_breadcrumbs {
20932            cx.emit(EditorEvent::BreadcrumbsChanged);
20933        }
20934
20935        let project_settings = ProjectSettings::get_global(cx);
20936        self.serialize_dirty_buffers =
20937            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20938
20939        if self.mode.is_full() {
20940            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20941            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20942            if self.show_inline_diagnostics != show_inline_diagnostics {
20943                self.show_inline_diagnostics = show_inline_diagnostics;
20944                self.refresh_inline_diagnostics(false, window, cx);
20945            }
20946
20947            if self.git_blame_inline_enabled != inline_blame_enabled {
20948                self.toggle_git_blame_inline_internal(false, window, cx);
20949            }
20950
20951            let minimap_settings = EditorSettings::get_global(cx).minimap;
20952            if self.minimap_visibility != MinimapVisibility::Disabled {
20953                if self.minimap_visibility.settings_visibility()
20954                    != minimap_settings.minimap_enabled()
20955                {
20956                    self.set_minimap_visibility(
20957                        MinimapVisibility::for_mode(self.mode(), cx),
20958                        window,
20959                        cx,
20960                    );
20961                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20962                    minimap_entity.update(cx, |minimap_editor, cx| {
20963                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20964                    })
20965                }
20966            }
20967        }
20968
20969        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20970            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20971        }) {
20972            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20973                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20974            }
20975            self.refresh_colors(false, None, window, cx);
20976        }
20977
20978        cx.notify();
20979    }
20980
20981    pub fn set_searchable(&mut self, searchable: bool) {
20982        self.searchable = searchable;
20983    }
20984
20985    pub fn searchable(&self) -> bool {
20986        self.searchable
20987    }
20988
20989    fn open_proposed_changes_editor(
20990        &mut self,
20991        _: &OpenProposedChangesEditor,
20992        window: &mut Window,
20993        cx: &mut Context<Self>,
20994    ) {
20995        let Some(workspace) = self.workspace() else {
20996            cx.propagate();
20997            return;
20998        };
20999
21000        let selections = self.selections.all::<usize>(cx);
21001        let multi_buffer = self.buffer.read(cx);
21002        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21003        let mut new_selections_by_buffer = HashMap::default();
21004        for selection in selections {
21005            for (buffer, range, _) in
21006                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21007            {
21008                let mut range = range.to_point(buffer);
21009                range.start.column = 0;
21010                range.end.column = buffer.line_len(range.end.row);
21011                new_selections_by_buffer
21012                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21013                    .or_insert(Vec::new())
21014                    .push(range)
21015            }
21016        }
21017
21018        let proposed_changes_buffers = new_selections_by_buffer
21019            .into_iter()
21020            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21021            .collect::<Vec<_>>();
21022        let proposed_changes_editor = cx.new(|cx| {
21023            ProposedChangesEditor::new(
21024                "Proposed changes",
21025                proposed_changes_buffers,
21026                self.project.clone(),
21027                window,
21028                cx,
21029            )
21030        });
21031
21032        window.defer(cx, move |window, cx| {
21033            workspace.update(cx, |workspace, cx| {
21034                workspace.active_pane().update(cx, |pane, cx| {
21035                    pane.add_item(
21036                        Box::new(proposed_changes_editor),
21037                        true,
21038                        true,
21039                        None,
21040                        window,
21041                        cx,
21042                    );
21043                });
21044            });
21045        });
21046    }
21047
21048    pub fn open_excerpts_in_split(
21049        &mut self,
21050        _: &OpenExcerptsSplit,
21051        window: &mut Window,
21052        cx: &mut Context<Self>,
21053    ) {
21054        self.open_excerpts_common(None, true, window, cx)
21055    }
21056
21057    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21058        self.open_excerpts_common(None, false, window, cx)
21059    }
21060
21061    fn open_excerpts_common(
21062        &mut self,
21063        jump_data: Option<JumpData>,
21064        split: bool,
21065        window: &mut Window,
21066        cx: &mut Context<Self>,
21067    ) {
21068        let Some(workspace) = self.workspace() else {
21069            cx.propagate();
21070            return;
21071        };
21072
21073        if self.buffer.read(cx).is_singleton() {
21074            cx.propagate();
21075            return;
21076        }
21077
21078        let mut new_selections_by_buffer = HashMap::default();
21079        match &jump_data {
21080            Some(JumpData::MultiBufferPoint {
21081                excerpt_id,
21082                position,
21083                anchor,
21084                line_offset_from_top,
21085            }) => {
21086                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21087                if let Some(buffer) = multi_buffer_snapshot
21088                    .buffer_id_for_excerpt(*excerpt_id)
21089                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21090                {
21091                    let buffer_snapshot = buffer.read(cx).snapshot();
21092                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21093                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21094                    } else {
21095                        buffer_snapshot.clip_point(*position, Bias::Left)
21096                    };
21097                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21098                    new_selections_by_buffer.insert(
21099                        buffer,
21100                        (
21101                            vec![jump_to_offset..jump_to_offset],
21102                            Some(*line_offset_from_top),
21103                        ),
21104                    );
21105                }
21106            }
21107            Some(JumpData::MultiBufferRow {
21108                row,
21109                line_offset_from_top,
21110            }) => {
21111                let point = MultiBufferPoint::new(row.0, 0);
21112                if let Some((buffer, buffer_point, _)) =
21113                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21114                {
21115                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21116                    new_selections_by_buffer
21117                        .entry(buffer)
21118                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21119                        .0
21120                        .push(buffer_offset..buffer_offset)
21121                }
21122            }
21123            None => {
21124                let selections = self.selections.all::<usize>(cx);
21125                let multi_buffer = self.buffer.read(cx);
21126                for selection in selections {
21127                    for (snapshot, range, _, anchor) in multi_buffer
21128                        .snapshot(cx)
21129                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21130                    {
21131                        if let Some(anchor) = anchor {
21132                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21133                            else {
21134                                continue;
21135                            };
21136                            let offset = text::ToOffset::to_offset(
21137                                &anchor.text_anchor,
21138                                &buffer_handle.read(cx).snapshot(),
21139                            );
21140                            let range = offset..offset;
21141                            new_selections_by_buffer
21142                                .entry(buffer_handle)
21143                                .or_insert((Vec::new(), None))
21144                                .0
21145                                .push(range)
21146                        } else {
21147                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21148                            else {
21149                                continue;
21150                            };
21151                            new_selections_by_buffer
21152                                .entry(buffer_handle)
21153                                .or_insert((Vec::new(), None))
21154                                .0
21155                                .push(range)
21156                        }
21157                    }
21158                }
21159            }
21160        }
21161
21162        new_selections_by_buffer
21163            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21164
21165        if new_selections_by_buffer.is_empty() {
21166            return;
21167        }
21168
21169        // We defer the pane interaction because we ourselves are a workspace item
21170        // and activating a new item causes the pane to call a method on us reentrantly,
21171        // which panics if we're on the stack.
21172        window.defer(cx, move |window, cx| {
21173            workspace.update(cx, |workspace, cx| {
21174                let pane = if split {
21175                    workspace.adjacent_pane(window, cx)
21176                } else {
21177                    workspace.active_pane().clone()
21178                };
21179
21180                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21181                    let editor = buffer
21182                        .read(cx)
21183                        .file()
21184                        .is_none()
21185                        .then(|| {
21186                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21187                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21188                            // Instead, we try to activate the existing editor in the pane first.
21189                            let (editor, pane_item_index) =
21190                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21191                                    let editor = item.downcast::<Editor>()?;
21192                                    let singleton_buffer =
21193                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21194                                    if singleton_buffer == buffer {
21195                                        Some((editor, i))
21196                                    } else {
21197                                        None
21198                                    }
21199                                })?;
21200                            pane.update(cx, |pane, cx| {
21201                                pane.activate_item(pane_item_index, true, true, window, cx)
21202                            });
21203                            Some(editor)
21204                        })
21205                        .flatten()
21206                        .unwrap_or_else(|| {
21207                            workspace.open_project_item::<Self>(
21208                                pane.clone(),
21209                                buffer,
21210                                true,
21211                                true,
21212                                window,
21213                                cx,
21214                            )
21215                        });
21216
21217                    editor.update(cx, |editor, cx| {
21218                        let autoscroll = match scroll_offset {
21219                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21220                            None => Autoscroll::newest(),
21221                        };
21222                        let nav_history = editor.nav_history.take();
21223                        editor.change_selections(
21224                            SelectionEffects::scroll(autoscroll),
21225                            window,
21226                            cx,
21227                            |s| {
21228                                s.select_ranges(ranges);
21229                            },
21230                        );
21231                        editor.nav_history = nav_history;
21232                    });
21233                }
21234            })
21235        });
21236    }
21237
21238    // For now, don't allow opening excerpts in buffers that aren't backed by
21239    // regular project files.
21240    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21241        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21242    }
21243
21244    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21245        let snapshot = self.buffer.read(cx).read(cx);
21246        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21247        Some(
21248            ranges
21249                .iter()
21250                .map(move |range| {
21251                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21252                })
21253                .collect(),
21254        )
21255    }
21256
21257    fn selection_replacement_ranges(
21258        &self,
21259        range: Range<OffsetUtf16>,
21260        cx: &mut App,
21261    ) -> Vec<Range<OffsetUtf16>> {
21262        let selections = self.selections.all::<OffsetUtf16>(cx);
21263        let newest_selection = selections
21264            .iter()
21265            .max_by_key(|selection| selection.id)
21266            .unwrap();
21267        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21268        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21269        let snapshot = self.buffer.read(cx).read(cx);
21270        selections
21271            .into_iter()
21272            .map(|mut selection| {
21273                selection.start.0 =
21274                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21275                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21276                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21277                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21278            })
21279            .collect()
21280    }
21281
21282    fn report_editor_event(
21283        &self,
21284        reported_event: ReportEditorEvent,
21285        file_extension: Option<String>,
21286        cx: &App,
21287    ) {
21288        if cfg!(any(test, feature = "test-support")) {
21289            return;
21290        }
21291
21292        let Some(project) = &self.project else { return };
21293
21294        // If None, we are in a file without an extension
21295        let file = self
21296            .buffer
21297            .read(cx)
21298            .as_singleton()
21299            .and_then(|b| b.read(cx).file());
21300        let file_extension = file_extension.or(file
21301            .as_ref()
21302            .and_then(|file| Path::new(file.file_name(cx)).extension())
21303            .and_then(|e| e.to_str())
21304            .map(|a| a.to_string()));
21305
21306        let vim_mode = vim_enabled(cx);
21307
21308        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21309        let copilot_enabled = edit_predictions_provider
21310            == language::language_settings::EditPredictionProvider::Copilot;
21311        let copilot_enabled_for_language = self
21312            .buffer
21313            .read(cx)
21314            .language_settings(cx)
21315            .show_edit_predictions;
21316
21317        let project = project.read(cx);
21318        let event_type = reported_event.event_type();
21319
21320        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21321            telemetry::event!(
21322                event_type,
21323                type = if auto_saved {"autosave"} else {"manual"},
21324                file_extension,
21325                vim_mode,
21326                copilot_enabled,
21327                copilot_enabled_for_language,
21328                edit_predictions_provider,
21329                is_via_ssh = project.is_via_remote_server(),
21330            );
21331        } else {
21332            telemetry::event!(
21333                event_type,
21334                file_extension,
21335                vim_mode,
21336                copilot_enabled,
21337                copilot_enabled_for_language,
21338                edit_predictions_provider,
21339                is_via_ssh = project.is_via_remote_server(),
21340            );
21341        };
21342    }
21343
21344    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21345    /// with each line being an array of {text, highlight} objects.
21346    fn copy_highlight_json(
21347        &mut self,
21348        _: &CopyHighlightJson,
21349        window: &mut Window,
21350        cx: &mut Context<Self>,
21351    ) {
21352        #[derive(Serialize)]
21353        struct Chunk<'a> {
21354            text: String,
21355            highlight: Option<&'a str>,
21356        }
21357
21358        let snapshot = self.buffer.read(cx).snapshot(cx);
21359        let range = self
21360            .selected_text_range(false, window, cx)
21361            .and_then(|selection| {
21362                if selection.range.is_empty() {
21363                    None
21364                } else {
21365                    Some(selection.range)
21366                }
21367            })
21368            .unwrap_or_else(|| 0..snapshot.len());
21369
21370        let chunks = snapshot.chunks(range, true);
21371        let mut lines = Vec::new();
21372        let mut line: VecDeque<Chunk> = VecDeque::new();
21373
21374        let Some(style) = self.style.as_ref() else {
21375            return;
21376        };
21377
21378        for chunk in chunks {
21379            let highlight = chunk
21380                .syntax_highlight_id
21381                .and_then(|id| id.name(&style.syntax));
21382            let mut chunk_lines = chunk.text.split('\n').peekable();
21383            while let Some(text) = chunk_lines.next() {
21384                let mut merged_with_last_token = false;
21385                if let Some(last_token) = line.back_mut()
21386                    && last_token.highlight == highlight
21387                {
21388                    last_token.text.push_str(text);
21389                    merged_with_last_token = true;
21390                }
21391
21392                if !merged_with_last_token {
21393                    line.push_back(Chunk {
21394                        text: text.into(),
21395                        highlight,
21396                    });
21397                }
21398
21399                if chunk_lines.peek().is_some() {
21400                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21401                        line.pop_front();
21402                    }
21403                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21404                        line.pop_back();
21405                    }
21406
21407                    lines.push(mem::take(&mut line));
21408                }
21409            }
21410        }
21411
21412        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21413            return;
21414        };
21415        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21416    }
21417
21418    pub fn open_context_menu(
21419        &mut self,
21420        _: &OpenContextMenu,
21421        window: &mut Window,
21422        cx: &mut Context<Self>,
21423    ) {
21424        self.request_autoscroll(Autoscroll::newest(), cx);
21425        let position = self.selections.newest_display(cx).start;
21426        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21427    }
21428
21429    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21430        &self.inlay_hint_cache
21431    }
21432
21433    pub fn replay_insert_event(
21434        &mut self,
21435        text: &str,
21436        relative_utf16_range: Option<Range<isize>>,
21437        window: &mut Window,
21438        cx: &mut Context<Self>,
21439    ) {
21440        if !self.input_enabled {
21441            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21442            return;
21443        }
21444        if let Some(relative_utf16_range) = relative_utf16_range {
21445            let selections = self.selections.all::<OffsetUtf16>(cx);
21446            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21447                let new_ranges = selections.into_iter().map(|range| {
21448                    let start = OffsetUtf16(
21449                        range
21450                            .head()
21451                            .0
21452                            .saturating_add_signed(relative_utf16_range.start),
21453                    );
21454                    let end = OffsetUtf16(
21455                        range
21456                            .head()
21457                            .0
21458                            .saturating_add_signed(relative_utf16_range.end),
21459                    );
21460                    start..end
21461                });
21462                s.select_ranges(new_ranges);
21463            });
21464        }
21465
21466        self.handle_input(text, window, cx);
21467    }
21468
21469    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21470        let Some(provider) = self.semantics_provider.as_ref() else {
21471            return false;
21472        };
21473
21474        let mut supports = false;
21475        self.buffer().update(cx, |this, cx| {
21476            this.for_each_buffer(|buffer| {
21477                supports |= provider.supports_inlay_hints(buffer, cx);
21478            });
21479        });
21480
21481        supports
21482    }
21483
21484    pub fn is_focused(&self, window: &Window) -> bool {
21485        self.focus_handle.is_focused(window)
21486    }
21487
21488    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21489        cx.emit(EditorEvent::Focused);
21490
21491        if let Some(descendant) = self
21492            .last_focused_descendant
21493            .take()
21494            .and_then(|descendant| descendant.upgrade())
21495        {
21496            window.focus(&descendant);
21497        } else {
21498            if let Some(blame) = self.blame.as_ref() {
21499                blame.update(cx, GitBlame::focus)
21500            }
21501
21502            self.blink_manager.update(cx, BlinkManager::enable);
21503            self.show_cursor_names(window, cx);
21504            self.buffer.update(cx, |buffer, cx| {
21505                buffer.finalize_last_transaction(cx);
21506                if self.leader_id.is_none() {
21507                    buffer.set_active_selections(
21508                        &self.selections.disjoint_anchors_arc(),
21509                        self.selections.line_mode(),
21510                        self.cursor_shape,
21511                        cx,
21512                    );
21513                }
21514            });
21515        }
21516    }
21517
21518    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21519        cx.emit(EditorEvent::FocusedIn)
21520    }
21521
21522    fn handle_focus_out(
21523        &mut self,
21524        event: FocusOutEvent,
21525        _window: &mut Window,
21526        cx: &mut Context<Self>,
21527    ) {
21528        if event.blurred != self.focus_handle {
21529            self.last_focused_descendant = Some(event.blurred);
21530        }
21531        self.selection_drag_state = SelectionDragState::None;
21532        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21533    }
21534
21535    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21536        self.blink_manager.update(cx, BlinkManager::disable);
21537        self.buffer
21538            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21539
21540        if let Some(blame) = self.blame.as_ref() {
21541            blame.update(cx, GitBlame::blur)
21542        }
21543        if !self.hover_state.focused(window, cx) {
21544            hide_hover(self, cx);
21545        }
21546        if !self
21547            .context_menu
21548            .borrow()
21549            .as_ref()
21550            .is_some_and(|context_menu| context_menu.focused(window, cx))
21551        {
21552            self.hide_context_menu(window, cx);
21553        }
21554        self.take_active_edit_prediction(cx);
21555        cx.emit(EditorEvent::Blurred);
21556        cx.notify();
21557    }
21558
21559    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21560        let mut pending: String = window
21561            .pending_input_keystrokes()
21562            .into_iter()
21563            .flatten()
21564            .filter_map(|keystroke| {
21565                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21566                    keystroke.key_char.clone()
21567                } else {
21568                    None
21569                }
21570            })
21571            .collect();
21572
21573        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21574            pending = "".to_string();
21575        }
21576
21577        let existing_pending = self
21578            .text_highlights::<PendingInput>(cx)
21579            .map(|(_, ranges)| ranges.to_vec());
21580        if existing_pending.is_none() && pending.is_empty() {
21581            return;
21582        }
21583        let transaction =
21584            self.transact(window, cx, |this, window, cx| {
21585                let selections = this.selections.all::<usize>(cx);
21586                let edits = selections
21587                    .iter()
21588                    .map(|selection| (selection.end..selection.end, pending.clone()));
21589                this.edit(edits, cx);
21590                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21591                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21592                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21593                    }));
21594                });
21595                if let Some(existing_ranges) = existing_pending {
21596                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21597                    this.edit(edits, cx);
21598                }
21599            });
21600
21601        let snapshot = self.snapshot(window, cx);
21602        let ranges = self
21603            .selections
21604            .all::<usize>(cx)
21605            .into_iter()
21606            .map(|selection| {
21607                snapshot.buffer_snapshot().anchor_after(selection.end)
21608                    ..snapshot
21609                        .buffer_snapshot()
21610                        .anchor_before(selection.end + pending.len())
21611            })
21612            .collect();
21613
21614        if pending.is_empty() {
21615            self.clear_highlights::<PendingInput>(cx);
21616        } else {
21617            self.highlight_text::<PendingInput>(
21618                ranges,
21619                HighlightStyle {
21620                    underline: Some(UnderlineStyle {
21621                        thickness: px(1.),
21622                        color: None,
21623                        wavy: false,
21624                    }),
21625                    ..Default::default()
21626                },
21627                cx,
21628            );
21629        }
21630
21631        self.ime_transaction = self.ime_transaction.or(transaction);
21632        if let Some(transaction) = self.ime_transaction {
21633            self.buffer.update(cx, |buffer, cx| {
21634                buffer.group_until_transaction(transaction, cx);
21635            });
21636        }
21637
21638        if self.text_highlights::<PendingInput>(cx).is_none() {
21639            self.ime_transaction.take();
21640        }
21641    }
21642
21643    pub fn register_action_renderer(
21644        &mut self,
21645        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21646    ) -> Subscription {
21647        let id = self.next_editor_action_id.post_inc();
21648        self.editor_actions
21649            .borrow_mut()
21650            .insert(id, Box::new(listener));
21651
21652        let editor_actions = self.editor_actions.clone();
21653        Subscription::new(move || {
21654            editor_actions.borrow_mut().remove(&id);
21655        })
21656    }
21657
21658    pub fn register_action<A: Action>(
21659        &mut self,
21660        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21661    ) -> Subscription {
21662        let id = self.next_editor_action_id.post_inc();
21663        let listener = Arc::new(listener);
21664        self.editor_actions.borrow_mut().insert(
21665            id,
21666            Box::new(move |_, window, _| {
21667                let listener = listener.clone();
21668                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21669                    let action = action.downcast_ref().unwrap();
21670                    if phase == DispatchPhase::Bubble {
21671                        listener(action, window, cx)
21672                    }
21673                })
21674            }),
21675        );
21676
21677        let editor_actions = self.editor_actions.clone();
21678        Subscription::new(move || {
21679            editor_actions.borrow_mut().remove(&id);
21680        })
21681    }
21682
21683    pub fn file_header_size(&self) -> u32 {
21684        FILE_HEADER_HEIGHT
21685    }
21686
21687    pub fn restore(
21688        &mut self,
21689        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21690        window: &mut Window,
21691        cx: &mut Context<Self>,
21692    ) {
21693        let workspace = self.workspace();
21694        let project = self.project();
21695        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21696            let mut tasks = Vec::new();
21697            for (buffer_id, changes) in revert_changes {
21698                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21699                    buffer.update(cx, |buffer, cx| {
21700                        buffer.edit(
21701                            changes
21702                                .into_iter()
21703                                .map(|(range, text)| (range, text.to_string())),
21704                            None,
21705                            cx,
21706                        );
21707                    });
21708
21709                    if let Some(project) =
21710                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21711                    {
21712                        project.update(cx, |project, cx| {
21713                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21714                        })
21715                    }
21716                }
21717            }
21718            tasks
21719        });
21720        cx.spawn_in(window, async move |_, cx| {
21721            for (buffer, task) in save_tasks {
21722                let result = task.await;
21723                if result.is_err() {
21724                    let Some(path) = buffer
21725                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21726                        .ok()
21727                    else {
21728                        continue;
21729                    };
21730                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21731                        let Some(task) = cx
21732                            .update_window_entity(workspace, |workspace, window, cx| {
21733                                workspace
21734                                    .open_path_preview(path, None, false, false, false, window, cx)
21735                            })
21736                            .ok()
21737                        else {
21738                            continue;
21739                        };
21740                        task.await.log_err();
21741                    }
21742                }
21743            }
21744        })
21745        .detach();
21746        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21747            selections.refresh()
21748        });
21749    }
21750
21751    pub fn to_pixel_point(
21752        &self,
21753        source: multi_buffer::Anchor,
21754        editor_snapshot: &EditorSnapshot,
21755        window: &mut Window,
21756    ) -> Option<gpui::Point<Pixels>> {
21757        let source_point = source.to_display_point(editor_snapshot);
21758        self.display_to_pixel_point(source_point, editor_snapshot, window)
21759    }
21760
21761    pub fn display_to_pixel_point(
21762        &self,
21763        source: DisplayPoint,
21764        editor_snapshot: &EditorSnapshot,
21765        window: &mut Window,
21766    ) -> Option<gpui::Point<Pixels>> {
21767        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21768        let text_layout_details = self.text_layout_details(window);
21769        let scroll_top = text_layout_details
21770            .scroll_anchor
21771            .scroll_position(editor_snapshot)
21772            .y;
21773
21774        if source.row().as_f64() < scroll_top.floor() {
21775            return None;
21776        }
21777        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21778        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21779        Some(gpui::Point::new(source_x, source_y))
21780    }
21781
21782    pub fn has_visible_completions_menu(&self) -> bool {
21783        !self.edit_prediction_preview_is_active()
21784            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21785                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21786            })
21787    }
21788
21789    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21790        if self.mode.is_minimap() {
21791            return;
21792        }
21793        self.addons
21794            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21795    }
21796
21797    pub fn unregister_addon<T: Addon>(&mut self) {
21798        self.addons.remove(&std::any::TypeId::of::<T>());
21799    }
21800
21801    pub fn addon<T: Addon>(&self) -> Option<&T> {
21802        let type_id = std::any::TypeId::of::<T>();
21803        self.addons
21804            .get(&type_id)
21805            .and_then(|item| item.to_any().downcast_ref::<T>())
21806    }
21807
21808    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21809        let type_id = std::any::TypeId::of::<T>();
21810        self.addons
21811            .get_mut(&type_id)
21812            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21813    }
21814
21815    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21816        let text_layout_details = self.text_layout_details(window);
21817        let style = &text_layout_details.editor_style;
21818        let font_id = window.text_system().resolve_font(&style.text.font());
21819        let font_size = style.text.font_size.to_pixels(window.rem_size());
21820        let line_height = style.text.line_height_in_pixels(window.rem_size());
21821        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21822        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21823
21824        CharacterDimensions {
21825            em_width,
21826            em_advance,
21827            line_height,
21828        }
21829    }
21830
21831    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21832        self.load_diff_task.clone()
21833    }
21834
21835    fn read_metadata_from_db(
21836        &mut self,
21837        item_id: u64,
21838        workspace_id: WorkspaceId,
21839        window: &mut Window,
21840        cx: &mut Context<Editor>,
21841    ) {
21842        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21843            && !self.mode.is_minimap()
21844            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21845        {
21846            let buffer_snapshot = OnceCell::new();
21847
21848            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21849                && !folds.is_empty()
21850            {
21851                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21852                self.fold_ranges(
21853                    folds
21854                        .into_iter()
21855                        .map(|(start, end)| {
21856                            snapshot.clip_offset(start, Bias::Left)
21857                                ..snapshot.clip_offset(end, Bias::Right)
21858                        })
21859                        .collect(),
21860                    false,
21861                    window,
21862                    cx,
21863                );
21864            }
21865
21866            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21867                && !selections.is_empty()
21868            {
21869                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21870                // skip adding the initial selection to selection history
21871                self.selection_history.mode = SelectionHistoryMode::Skipping;
21872                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21873                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21874                        snapshot.clip_offset(start, Bias::Left)
21875                            ..snapshot.clip_offset(end, Bias::Right)
21876                    }));
21877                });
21878                self.selection_history.mode = SelectionHistoryMode::Normal;
21879            };
21880        }
21881
21882        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21883    }
21884
21885    fn update_lsp_data(
21886        &mut self,
21887        ignore_cache: bool,
21888        for_buffer: Option<BufferId>,
21889        window: &mut Window,
21890        cx: &mut Context<'_, Self>,
21891    ) {
21892        self.pull_diagnostics(for_buffer, window, cx);
21893        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21894    }
21895}
21896
21897fn edit_for_markdown_paste<'a>(
21898    buffer: &MultiBufferSnapshot,
21899    range: Range<usize>,
21900    to_insert: &'a str,
21901    url: Option<url::Url>,
21902) -> (Range<usize>, Cow<'a, str>) {
21903    if url.is_none() {
21904        return (range, Cow::Borrowed(to_insert));
21905    };
21906
21907    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21908
21909    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21910        Cow::Borrowed(to_insert)
21911    } else {
21912        Cow::Owned(format!("[{old_text}]({to_insert})"))
21913    };
21914    (range, new_text)
21915}
21916
21917fn vim_enabled(cx: &App) -> bool {
21918    vim_mode_setting::VimModeSetting::try_get(cx)
21919        .map(|vim_mode| vim_mode.0)
21920        .unwrap_or(false)
21921}
21922
21923fn process_completion_for_edit(
21924    completion: &Completion,
21925    intent: CompletionIntent,
21926    buffer: &Entity<Buffer>,
21927    cursor_position: &text::Anchor,
21928    cx: &mut Context<Editor>,
21929) -> CompletionEdit {
21930    let buffer = buffer.read(cx);
21931    let buffer_snapshot = buffer.snapshot();
21932    let (snippet, new_text) = if completion.is_snippet() {
21933        let mut snippet_source = completion.new_text.clone();
21934        // Workaround for typescript language server issues so that methods don't expand within
21935        // strings and functions with type expressions. The previous point is used because the query
21936        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21937        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
21938        let previous_point = if previous_point.column > 0 {
21939            cursor_position.to_previous_offset(&buffer_snapshot)
21940        } else {
21941            cursor_position.to_offset(&buffer_snapshot)
21942        };
21943        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21944            && scope.prefers_label_for_snippet_in_completion()
21945            && let Some(label) = completion.label()
21946            && matches!(
21947                completion.kind(),
21948                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21949            )
21950        {
21951            snippet_source = label;
21952        }
21953        match Snippet::parse(&snippet_source).log_err() {
21954            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21955            None => (None, completion.new_text.clone()),
21956        }
21957    } else {
21958        (None, completion.new_text.clone())
21959    };
21960
21961    let mut range_to_replace = {
21962        let replace_range = &completion.replace_range;
21963        if let CompletionSource::Lsp {
21964            insert_range: Some(insert_range),
21965            ..
21966        } = &completion.source
21967        {
21968            debug_assert_eq!(
21969                insert_range.start, replace_range.start,
21970                "insert_range and replace_range should start at the same position"
21971            );
21972            debug_assert!(
21973                insert_range
21974                    .start
21975                    .cmp(cursor_position, &buffer_snapshot)
21976                    .is_le(),
21977                "insert_range should start before or at cursor position"
21978            );
21979            debug_assert!(
21980                replace_range
21981                    .start
21982                    .cmp(cursor_position, &buffer_snapshot)
21983                    .is_le(),
21984                "replace_range should start before or at cursor position"
21985            );
21986
21987            let should_replace = match intent {
21988                CompletionIntent::CompleteWithInsert => false,
21989                CompletionIntent::CompleteWithReplace => true,
21990                CompletionIntent::Complete | CompletionIntent::Compose => {
21991                    let insert_mode =
21992                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21993                            .completions
21994                            .lsp_insert_mode;
21995                    match insert_mode {
21996                        LspInsertMode::Insert => false,
21997                        LspInsertMode::Replace => true,
21998                        LspInsertMode::ReplaceSubsequence => {
21999                            let mut text_to_replace = buffer.chars_for_range(
22000                                buffer.anchor_before(replace_range.start)
22001                                    ..buffer.anchor_after(replace_range.end),
22002                            );
22003                            let mut current_needle = text_to_replace.next();
22004                            for haystack_ch in completion.label.text.chars() {
22005                                if let Some(needle_ch) = current_needle
22006                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22007                                {
22008                                    current_needle = text_to_replace.next();
22009                                }
22010                            }
22011                            current_needle.is_none()
22012                        }
22013                        LspInsertMode::ReplaceSuffix => {
22014                            if replace_range
22015                                .end
22016                                .cmp(cursor_position, &buffer_snapshot)
22017                                .is_gt()
22018                            {
22019                                let range_after_cursor = *cursor_position..replace_range.end;
22020                                let text_after_cursor = buffer
22021                                    .text_for_range(
22022                                        buffer.anchor_before(range_after_cursor.start)
22023                                            ..buffer.anchor_after(range_after_cursor.end),
22024                                    )
22025                                    .collect::<String>()
22026                                    .to_ascii_lowercase();
22027                                completion
22028                                    .label
22029                                    .text
22030                                    .to_ascii_lowercase()
22031                                    .ends_with(&text_after_cursor)
22032                            } else {
22033                                true
22034                            }
22035                        }
22036                    }
22037                }
22038            };
22039
22040            if should_replace {
22041                replace_range.clone()
22042            } else {
22043                insert_range.clone()
22044            }
22045        } else {
22046            replace_range.clone()
22047        }
22048    };
22049
22050    if range_to_replace
22051        .end
22052        .cmp(cursor_position, &buffer_snapshot)
22053        .is_lt()
22054    {
22055        range_to_replace.end = *cursor_position;
22056    }
22057
22058    CompletionEdit {
22059        new_text,
22060        replace_range: range_to_replace.to_offset(buffer),
22061        snippet,
22062    }
22063}
22064
22065struct CompletionEdit {
22066    new_text: String,
22067    replace_range: Range<usize>,
22068    snippet: Option<Snippet>,
22069}
22070
22071fn insert_extra_newline_brackets(
22072    buffer: &MultiBufferSnapshot,
22073    range: Range<usize>,
22074    language: &language::LanguageScope,
22075) -> bool {
22076    let leading_whitespace_len = buffer
22077        .reversed_chars_at(range.start)
22078        .take_while(|c| c.is_whitespace() && *c != '\n')
22079        .map(|c| c.len_utf8())
22080        .sum::<usize>();
22081    let trailing_whitespace_len = buffer
22082        .chars_at(range.end)
22083        .take_while(|c| c.is_whitespace() && *c != '\n')
22084        .map(|c| c.len_utf8())
22085        .sum::<usize>();
22086    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22087
22088    language.brackets().any(|(pair, enabled)| {
22089        let pair_start = pair.start.trim_end();
22090        let pair_end = pair.end.trim_start();
22091
22092        enabled
22093            && pair.newline
22094            && buffer.contains_str_at(range.end, pair_end)
22095            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22096    })
22097}
22098
22099fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22100    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22101        [(buffer, range, _)] => (*buffer, range.clone()),
22102        _ => return false,
22103    };
22104    let pair = {
22105        let mut result: Option<BracketMatch> = None;
22106
22107        for pair in buffer
22108            .all_bracket_ranges(range.clone())
22109            .filter(move |pair| {
22110                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22111            })
22112        {
22113            let len = pair.close_range.end - pair.open_range.start;
22114
22115            if let Some(existing) = &result {
22116                let existing_len = existing.close_range.end - existing.open_range.start;
22117                if len > existing_len {
22118                    continue;
22119                }
22120            }
22121
22122            result = Some(pair);
22123        }
22124
22125        result
22126    };
22127    let Some(pair) = pair else {
22128        return false;
22129    };
22130    pair.newline_only
22131        && buffer
22132            .chars_for_range(pair.open_range.end..range.start)
22133            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22134            .all(|c| c.is_whitespace() && c != '\n')
22135}
22136
22137fn update_uncommitted_diff_for_buffer(
22138    editor: Entity<Editor>,
22139    project: &Entity<Project>,
22140    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22141    buffer: Entity<MultiBuffer>,
22142    cx: &mut App,
22143) -> Task<()> {
22144    let mut tasks = Vec::new();
22145    project.update(cx, |project, cx| {
22146        for buffer in buffers {
22147            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22148                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22149            }
22150        }
22151    });
22152    cx.spawn(async move |cx| {
22153        let diffs = future::join_all(tasks).await;
22154        if editor
22155            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22156            .unwrap_or(false)
22157        {
22158            return;
22159        }
22160
22161        buffer
22162            .update(cx, |buffer, cx| {
22163                for diff in diffs.into_iter().flatten() {
22164                    buffer.add_diff(diff, cx);
22165                }
22166            })
22167            .ok();
22168    })
22169}
22170
22171fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22172    let tab_size = tab_size.get() as usize;
22173    let mut width = offset;
22174
22175    for ch in text.chars() {
22176        width += if ch == '\t' {
22177            tab_size - (width % tab_size)
22178        } else {
22179            1
22180        };
22181    }
22182
22183    width - offset
22184}
22185
22186#[cfg(test)]
22187mod tests {
22188    use super::*;
22189
22190    #[test]
22191    fn test_string_size_with_expanded_tabs() {
22192        let nz = |val| NonZeroU32::new(val).unwrap();
22193        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22194        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22195        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22196        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22197        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22198        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22199        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22200        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22201    }
22202}
22203
22204/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22205struct WordBreakingTokenizer<'a> {
22206    input: &'a str,
22207}
22208
22209impl<'a> WordBreakingTokenizer<'a> {
22210    fn new(input: &'a str) -> Self {
22211        Self { input }
22212    }
22213}
22214
22215fn is_char_ideographic(ch: char) -> bool {
22216    use unicode_script::Script::*;
22217    use unicode_script::UnicodeScript;
22218    matches!(ch.script(), Han | Tangut | Yi)
22219}
22220
22221fn is_grapheme_ideographic(text: &str) -> bool {
22222    text.chars().any(is_char_ideographic)
22223}
22224
22225fn is_grapheme_whitespace(text: &str) -> bool {
22226    text.chars().any(|x| x.is_whitespace())
22227}
22228
22229fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22230    text.chars()
22231        .next()
22232        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22233}
22234
22235#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22236enum WordBreakToken<'a> {
22237    Word { token: &'a str, grapheme_len: usize },
22238    InlineWhitespace { token: &'a str, grapheme_len: usize },
22239    Newline,
22240}
22241
22242impl<'a> Iterator for WordBreakingTokenizer<'a> {
22243    /// Yields a span, the count of graphemes in the token, and whether it was
22244    /// whitespace. Note that it also breaks at word boundaries.
22245    type Item = WordBreakToken<'a>;
22246
22247    fn next(&mut self) -> Option<Self::Item> {
22248        use unicode_segmentation::UnicodeSegmentation;
22249        if self.input.is_empty() {
22250            return None;
22251        }
22252
22253        let mut iter = self.input.graphemes(true).peekable();
22254        let mut offset = 0;
22255        let mut grapheme_len = 0;
22256        if let Some(first_grapheme) = iter.next() {
22257            let is_newline = first_grapheme == "\n";
22258            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22259            offset += first_grapheme.len();
22260            grapheme_len += 1;
22261            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22262                if let Some(grapheme) = iter.peek().copied()
22263                    && should_stay_with_preceding_ideograph(grapheme)
22264                {
22265                    offset += grapheme.len();
22266                    grapheme_len += 1;
22267                }
22268            } else {
22269                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22270                let mut next_word_bound = words.peek().copied();
22271                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22272                    next_word_bound = words.next();
22273                }
22274                while let Some(grapheme) = iter.peek().copied() {
22275                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22276                        break;
22277                    };
22278                    if is_grapheme_whitespace(grapheme) != is_whitespace
22279                        || (grapheme == "\n") != is_newline
22280                    {
22281                        break;
22282                    };
22283                    offset += grapheme.len();
22284                    grapheme_len += 1;
22285                    iter.next();
22286                }
22287            }
22288            let token = &self.input[..offset];
22289            self.input = &self.input[offset..];
22290            if token == "\n" {
22291                Some(WordBreakToken::Newline)
22292            } else if is_whitespace {
22293                Some(WordBreakToken::InlineWhitespace {
22294                    token,
22295                    grapheme_len,
22296                })
22297            } else {
22298                Some(WordBreakToken::Word {
22299                    token,
22300                    grapheme_len,
22301                })
22302            }
22303        } else {
22304            None
22305        }
22306    }
22307}
22308
22309#[test]
22310fn test_word_breaking_tokenizer() {
22311    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22312        ("", &[]),
22313        ("  ", &[whitespace("  ", 2)]),
22314        ("Ʒ", &[word("Ʒ", 1)]),
22315        ("Ǽ", &[word("Ǽ", 1)]),
22316        ("", &[word("", 1)]),
22317        ("⋑⋑", &[word("⋑⋑", 2)]),
22318        (
22319            "原理,进而",
22320            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22321        ),
22322        (
22323            "hello world",
22324            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22325        ),
22326        (
22327            "hello, world",
22328            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22329        ),
22330        (
22331            "  hello world",
22332            &[
22333                whitespace("  ", 2),
22334                word("hello", 5),
22335                whitespace(" ", 1),
22336                word("world", 5),
22337            ],
22338        ),
22339        (
22340            "这是什么 \n 钢笔",
22341            &[
22342                word("", 1),
22343                word("", 1),
22344                word("", 1),
22345                word("", 1),
22346                whitespace(" ", 1),
22347                newline(),
22348                whitespace(" ", 1),
22349                word("", 1),
22350                word("", 1),
22351            ],
22352        ),
22353        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22354    ];
22355
22356    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22357        WordBreakToken::Word {
22358            token,
22359            grapheme_len,
22360        }
22361    }
22362
22363    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22364        WordBreakToken::InlineWhitespace {
22365            token,
22366            grapheme_len,
22367        }
22368    }
22369
22370    fn newline() -> WordBreakToken<'static> {
22371        WordBreakToken::Newline
22372    }
22373
22374    for (input, result) in tests {
22375        assert_eq!(
22376            WordBreakingTokenizer::new(input)
22377                .collect::<Vec<_>>()
22378                .as_slice(),
22379            *result,
22380        );
22381    }
22382}
22383
22384fn wrap_with_prefix(
22385    first_line_prefix: String,
22386    subsequent_lines_prefix: String,
22387    unwrapped_text: String,
22388    wrap_column: usize,
22389    tab_size: NonZeroU32,
22390    preserve_existing_whitespace: bool,
22391) -> String {
22392    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22393    let subsequent_lines_prefix_len =
22394        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22395    let mut wrapped_text = String::new();
22396    let mut current_line = first_line_prefix;
22397    let mut is_first_line = true;
22398
22399    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22400    let mut current_line_len = first_line_prefix_len;
22401    let mut in_whitespace = false;
22402    for token in tokenizer {
22403        let have_preceding_whitespace = in_whitespace;
22404        match token {
22405            WordBreakToken::Word {
22406                token,
22407                grapheme_len,
22408            } => {
22409                in_whitespace = false;
22410                let current_prefix_len = if is_first_line {
22411                    first_line_prefix_len
22412                } else {
22413                    subsequent_lines_prefix_len
22414                };
22415                if current_line_len + grapheme_len > wrap_column
22416                    && current_line_len != current_prefix_len
22417                {
22418                    wrapped_text.push_str(current_line.trim_end());
22419                    wrapped_text.push('\n');
22420                    is_first_line = false;
22421                    current_line = subsequent_lines_prefix.clone();
22422                    current_line_len = subsequent_lines_prefix_len;
22423                }
22424                current_line.push_str(token);
22425                current_line_len += grapheme_len;
22426            }
22427            WordBreakToken::InlineWhitespace {
22428                mut token,
22429                mut grapheme_len,
22430            } => {
22431                in_whitespace = true;
22432                if have_preceding_whitespace && !preserve_existing_whitespace {
22433                    continue;
22434                }
22435                if !preserve_existing_whitespace {
22436                    // Keep a single whitespace grapheme as-is
22437                    if let Some(first) =
22438                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22439                    {
22440                        token = first;
22441                    } else {
22442                        token = " ";
22443                    }
22444                    grapheme_len = 1;
22445                }
22446                let current_prefix_len = if is_first_line {
22447                    first_line_prefix_len
22448                } else {
22449                    subsequent_lines_prefix_len
22450                };
22451                if current_line_len + grapheme_len > wrap_column {
22452                    wrapped_text.push_str(current_line.trim_end());
22453                    wrapped_text.push('\n');
22454                    is_first_line = false;
22455                    current_line = subsequent_lines_prefix.clone();
22456                    current_line_len = subsequent_lines_prefix_len;
22457                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22458                    current_line.push_str(token);
22459                    current_line_len += grapheme_len;
22460                }
22461            }
22462            WordBreakToken::Newline => {
22463                in_whitespace = true;
22464                let current_prefix_len = if is_first_line {
22465                    first_line_prefix_len
22466                } else {
22467                    subsequent_lines_prefix_len
22468                };
22469                if preserve_existing_whitespace {
22470                    wrapped_text.push_str(current_line.trim_end());
22471                    wrapped_text.push('\n');
22472                    is_first_line = false;
22473                    current_line = subsequent_lines_prefix.clone();
22474                    current_line_len = subsequent_lines_prefix_len;
22475                } else if have_preceding_whitespace {
22476                    continue;
22477                } else if current_line_len + 1 > wrap_column
22478                    && current_line_len != current_prefix_len
22479                {
22480                    wrapped_text.push_str(current_line.trim_end());
22481                    wrapped_text.push('\n');
22482                    is_first_line = false;
22483                    current_line = subsequent_lines_prefix.clone();
22484                    current_line_len = subsequent_lines_prefix_len;
22485                } else if current_line_len != current_prefix_len {
22486                    current_line.push(' ');
22487                    current_line_len += 1;
22488                }
22489            }
22490        }
22491    }
22492
22493    if !current_line.is_empty() {
22494        wrapped_text.push_str(&current_line);
22495    }
22496    wrapped_text
22497}
22498
22499#[test]
22500fn test_wrap_with_prefix() {
22501    assert_eq!(
22502        wrap_with_prefix(
22503            "# ".to_string(),
22504            "# ".to_string(),
22505            "abcdefg".to_string(),
22506            4,
22507            NonZeroU32::new(4).unwrap(),
22508            false,
22509        ),
22510        "# abcdefg"
22511    );
22512    assert_eq!(
22513        wrap_with_prefix(
22514            "".to_string(),
22515            "".to_string(),
22516            "\thello world".to_string(),
22517            8,
22518            NonZeroU32::new(4).unwrap(),
22519            false,
22520        ),
22521        "hello\nworld"
22522    );
22523    assert_eq!(
22524        wrap_with_prefix(
22525            "// ".to_string(),
22526            "// ".to_string(),
22527            "xx \nyy zz aa bb cc".to_string(),
22528            12,
22529            NonZeroU32::new(4).unwrap(),
22530            false,
22531        ),
22532        "// xx yy zz\n// aa bb cc"
22533    );
22534    assert_eq!(
22535        wrap_with_prefix(
22536            String::new(),
22537            String::new(),
22538            "这是什么 \n 钢笔".to_string(),
22539            3,
22540            NonZeroU32::new(4).unwrap(),
22541            false,
22542        ),
22543        "这是什\n么 钢\n"
22544    );
22545    assert_eq!(
22546        wrap_with_prefix(
22547            String::new(),
22548            String::new(),
22549            format!("foo{}bar", '\u{2009}'), // thin space
22550            80,
22551            NonZeroU32::new(4).unwrap(),
22552            false,
22553        ),
22554        format!("foo{}bar", '\u{2009}')
22555    );
22556}
22557
22558pub trait CollaborationHub {
22559    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22560    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22561    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22562}
22563
22564impl CollaborationHub for Entity<Project> {
22565    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22566        self.read(cx).collaborators()
22567    }
22568
22569    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22570        self.read(cx).user_store().read(cx).participant_indices()
22571    }
22572
22573    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22574        let this = self.read(cx);
22575        let user_ids = this.collaborators().values().map(|c| c.user_id);
22576        this.user_store().read(cx).participant_names(user_ids, cx)
22577    }
22578}
22579
22580pub trait SemanticsProvider {
22581    fn hover(
22582        &self,
22583        buffer: &Entity<Buffer>,
22584        position: text::Anchor,
22585        cx: &mut App,
22586    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22587
22588    fn inline_values(
22589        &self,
22590        buffer_handle: Entity<Buffer>,
22591        range: Range<text::Anchor>,
22592        cx: &mut App,
22593    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22594
22595    fn inlay_hints(
22596        &self,
22597        buffer_handle: Entity<Buffer>,
22598        range: Range<text::Anchor>,
22599        cx: &mut App,
22600    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22601
22602    fn resolve_inlay_hint(
22603        &self,
22604        hint: InlayHint,
22605        buffer_handle: Entity<Buffer>,
22606        server_id: LanguageServerId,
22607        cx: &mut App,
22608    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22609
22610    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22611
22612    fn document_highlights(
22613        &self,
22614        buffer: &Entity<Buffer>,
22615        position: text::Anchor,
22616        cx: &mut App,
22617    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22618
22619    fn definitions(
22620        &self,
22621        buffer: &Entity<Buffer>,
22622        position: text::Anchor,
22623        kind: GotoDefinitionKind,
22624        cx: &mut App,
22625    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22626
22627    fn range_for_rename(
22628        &self,
22629        buffer: &Entity<Buffer>,
22630        position: text::Anchor,
22631        cx: &mut App,
22632    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22633
22634    fn perform_rename(
22635        &self,
22636        buffer: &Entity<Buffer>,
22637        position: text::Anchor,
22638        new_name: String,
22639        cx: &mut App,
22640    ) -> Option<Task<Result<ProjectTransaction>>>;
22641}
22642
22643pub trait CompletionProvider {
22644    fn completions(
22645        &self,
22646        excerpt_id: ExcerptId,
22647        buffer: &Entity<Buffer>,
22648        buffer_position: text::Anchor,
22649        trigger: CompletionContext,
22650        window: &mut Window,
22651        cx: &mut Context<Editor>,
22652    ) -> Task<Result<Vec<CompletionResponse>>>;
22653
22654    fn resolve_completions(
22655        &self,
22656        _buffer: Entity<Buffer>,
22657        _completion_indices: Vec<usize>,
22658        _completions: Rc<RefCell<Box<[Completion]>>>,
22659        _cx: &mut Context<Editor>,
22660    ) -> Task<Result<bool>> {
22661        Task::ready(Ok(false))
22662    }
22663
22664    fn apply_additional_edits_for_completion(
22665        &self,
22666        _buffer: Entity<Buffer>,
22667        _completions: Rc<RefCell<Box<[Completion]>>>,
22668        _completion_index: usize,
22669        _push_to_history: bool,
22670        _cx: &mut Context<Editor>,
22671    ) -> Task<Result<Option<language::Transaction>>> {
22672        Task::ready(Ok(None))
22673    }
22674
22675    fn is_completion_trigger(
22676        &self,
22677        buffer: &Entity<Buffer>,
22678        position: language::Anchor,
22679        text: &str,
22680        trigger_in_words: bool,
22681        menu_is_open: bool,
22682        cx: &mut Context<Editor>,
22683    ) -> bool;
22684
22685    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22686
22687    fn sort_completions(&self) -> bool {
22688        true
22689    }
22690
22691    fn filter_completions(&self) -> bool {
22692        true
22693    }
22694}
22695
22696pub trait CodeActionProvider {
22697    fn id(&self) -> Arc<str>;
22698
22699    fn code_actions(
22700        &self,
22701        buffer: &Entity<Buffer>,
22702        range: Range<text::Anchor>,
22703        window: &mut Window,
22704        cx: &mut App,
22705    ) -> Task<Result<Vec<CodeAction>>>;
22706
22707    fn apply_code_action(
22708        &self,
22709        buffer_handle: Entity<Buffer>,
22710        action: CodeAction,
22711        excerpt_id: ExcerptId,
22712        push_to_history: bool,
22713        window: &mut Window,
22714        cx: &mut App,
22715    ) -> Task<Result<ProjectTransaction>>;
22716}
22717
22718impl CodeActionProvider for Entity<Project> {
22719    fn id(&self) -> Arc<str> {
22720        "project".into()
22721    }
22722
22723    fn code_actions(
22724        &self,
22725        buffer: &Entity<Buffer>,
22726        range: Range<text::Anchor>,
22727        _window: &mut Window,
22728        cx: &mut App,
22729    ) -> Task<Result<Vec<CodeAction>>> {
22730        self.update(cx, |project, cx| {
22731            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22732            let code_actions = project.code_actions(buffer, range, None, cx);
22733            cx.background_spawn(async move {
22734                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22735                Ok(code_lens_actions
22736                    .context("code lens fetch")?
22737                    .into_iter()
22738                    .flatten()
22739                    .chain(
22740                        code_actions
22741                            .context("code action fetch")?
22742                            .into_iter()
22743                            .flatten(),
22744                    )
22745                    .collect())
22746            })
22747        })
22748    }
22749
22750    fn apply_code_action(
22751        &self,
22752        buffer_handle: Entity<Buffer>,
22753        action: CodeAction,
22754        _excerpt_id: ExcerptId,
22755        push_to_history: bool,
22756        _window: &mut Window,
22757        cx: &mut App,
22758    ) -> Task<Result<ProjectTransaction>> {
22759        self.update(cx, |project, cx| {
22760            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22761        })
22762    }
22763}
22764
22765fn snippet_completions(
22766    project: &Project,
22767    buffer: &Entity<Buffer>,
22768    buffer_position: text::Anchor,
22769    cx: &mut App,
22770) -> Task<Result<CompletionResponse>> {
22771    let languages = buffer.read(cx).languages_at(buffer_position);
22772    let snippet_store = project.snippets().read(cx);
22773
22774    let scopes: Vec<_> = languages
22775        .iter()
22776        .filter_map(|language| {
22777            let language_name = language.lsp_id();
22778            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22779
22780            if snippets.is_empty() {
22781                None
22782            } else {
22783                Some((language.default_scope(), snippets))
22784            }
22785        })
22786        .collect();
22787
22788    if scopes.is_empty() {
22789        return Task::ready(Ok(CompletionResponse {
22790            completions: vec![],
22791            display_options: CompletionDisplayOptions::default(),
22792            is_incomplete: false,
22793        }));
22794    }
22795
22796    let snapshot = buffer.read(cx).text_snapshot();
22797    let chars: String = snapshot
22798        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22799        .collect();
22800    let executor = cx.background_executor().clone();
22801
22802    cx.background_spawn(async move {
22803        let mut is_incomplete = false;
22804        let mut completions: Vec<Completion> = Vec::new();
22805        for (scope, snippets) in scopes.into_iter() {
22806            let classifier =
22807                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22808            let mut last_word = chars
22809                .chars()
22810                .take_while(|c| classifier.is_word(*c))
22811                .collect::<String>();
22812            last_word = last_word.chars().rev().collect();
22813
22814            if last_word.is_empty() {
22815                return Ok(CompletionResponse {
22816                    completions: vec![],
22817                    display_options: CompletionDisplayOptions::default(),
22818                    is_incomplete: true,
22819                });
22820            }
22821
22822            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22823            let to_lsp = |point: &text::Anchor| {
22824                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22825                point_to_lsp(end)
22826            };
22827            let lsp_end = to_lsp(&buffer_position);
22828
22829            let candidates = snippets
22830                .iter()
22831                .enumerate()
22832                .flat_map(|(ix, snippet)| {
22833                    snippet
22834                        .prefix
22835                        .iter()
22836                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22837                })
22838                .collect::<Vec<StringMatchCandidate>>();
22839
22840            const MAX_RESULTS: usize = 100;
22841            let mut matches = fuzzy::match_strings(
22842                &candidates,
22843                &last_word,
22844                last_word.chars().any(|c| c.is_uppercase()),
22845                true,
22846                MAX_RESULTS,
22847                &Default::default(),
22848                executor.clone(),
22849            )
22850            .await;
22851
22852            if matches.len() >= MAX_RESULTS {
22853                is_incomplete = true;
22854            }
22855
22856            // Remove all candidates where the query's start does not match the start of any word in the candidate
22857            if let Some(query_start) = last_word.chars().next() {
22858                matches.retain(|string_match| {
22859                    split_words(&string_match.string).any(|word| {
22860                        // Check that the first codepoint of the word as lowercase matches the first
22861                        // codepoint of the query as lowercase
22862                        word.chars()
22863                            .flat_map(|codepoint| codepoint.to_lowercase())
22864                            .zip(query_start.to_lowercase())
22865                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22866                    })
22867                });
22868            }
22869
22870            let matched_strings = matches
22871                .into_iter()
22872                .map(|m| m.string)
22873                .collect::<HashSet<_>>();
22874
22875            completions.extend(snippets.iter().filter_map(|snippet| {
22876                let matching_prefix = snippet
22877                    .prefix
22878                    .iter()
22879                    .find(|prefix| matched_strings.contains(*prefix))?;
22880                let start = as_offset - last_word.len();
22881                let start = snapshot.anchor_before(start);
22882                let range = start..buffer_position;
22883                let lsp_start = to_lsp(&start);
22884                let lsp_range = lsp::Range {
22885                    start: lsp_start,
22886                    end: lsp_end,
22887                };
22888                Some(Completion {
22889                    replace_range: range,
22890                    new_text: snippet.body.clone(),
22891                    source: CompletionSource::Lsp {
22892                        insert_range: None,
22893                        server_id: LanguageServerId(usize::MAX),
22894                        resolved: true,
22895                        lsp_completion: Box::new(lsp::CompletionItem {
22896                            label: snippet.prefix.first().unwrap().clone(),
22897                            kind: Some(CompletionItemKind::SNIPPET),
22898                            label_details: snippet.description.as_ref().map(|description| {
22899                                lsp::CompletionItemLabelDetails {
22900                                    detail: Some(description.clone()),
22901                                    description: None,
22902                                }
22903                            }),
22904                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22905                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22906                                lsp::InsertReplaceEdit {
22907                                    new_text: snippet.body.clone(),
22908                                    insert: lsp_range,
22909                                    replace: lsp_range,
22910                                },
22911                            )),
22912                            filter_text: Some(snippet.body.clone()),
22913                            sort_text: Some(char::MAX.to_string()),
22914                            ..lsp::CompletionItem::default()
22915                        }),
22916                        lsp_defaults: None,
22917                    },
22918                    label: CodeLabel {
22919                        text: matching_prefix.clone(),
22920                        runs: Vec::new(),
22921                        filter_range: 0..matching_prefix.len(),
22922                    },
22923                    icon_path: None,
22924                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22925                        single_line: snippet.name.clone().into(),
22926                        plain_text: snippet
22927                            .description
22928                            .clone()
22929                            .map(|description| description.into()),
22930                    }),
22931                    insert_text_mode: None,
22932                    confirm: None,
22933                })
22934            }))
22935        }
22936
22937        Ok(CompletionResponse {
22938            completions,
22939            display_options: CompletionDisplayOptions::default(),
22940            is_incomplete,
22941        })
22942    })
22943}
22944
22945impl CompletionProvider for Entity<Project> {
22946    fn completions(
22947        &self,
22948        _excerpt_id: ExcerptId,
22949        buffer: &Entity<Buffer>,
22950        buffer_position: text::Anchor,
22951        options: CompletionContext,
22952        _window: &mut Window,
22953        cx: &mut Context<Editor>,
22954    ) -> Task<Result<Vec<CompletionResponse>>> {
22955        self.update(cx, |project, cx| {
22956            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22957            let project_completions = project.completions(buffer, buffer_position, options, cx);
22958            cx.background_spawn(async move {
22959                let mut responses = project_completions.await?;
22960                let snippets = snippets.await?;
22961                if !snippets.completions.is_empty() {
22962                    responses.push(snippets);
22963                }
22964                Ok(responses)
22965            })
22966        })
22967    }
22968
22969    fn resolve_completions(
22970        &self,
22971        buffer: Entity<Buffer>,
22972        completion_indices: Vec<usize>,
22973        completions: Rc<RefCell<Box<[Completion]>>>,
22974        cx: &mut Context<Editor>,
22975    ) -> Task<Result<bool>> {
22976        self.update(cx, |project, cx| {
22977            project.lsp_store().update(cx, |lsp_store, cx| {
22978                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22979            })
22980        })
22981    }
22982
22983    fn apply_additional_edits_for_completion(
22984        &self,
22985        buffer: Entity<Buffer>,
22986        completions: Rc<RefCell<Box<[Completion]>>>,
22987        completion_index: usize,
22988        push_to_history: bool,
22989        cx: &mut Context<Editor>,
22990    ) -> Task<Result<Option<language::Transaction>>> {
22991        self.update(cx, |project, cx| {
22992            project.lsp_store().update(cx, |lsp_store, cx| {
22993                lsp_store.apply_additional_edits_for_completion(
22994                    buffer,
22995                    completions,
22996                    completion_index,
22997                    push_to_history,
22998                    cx,
22999                )
23000            })
23001        })
23002    }
23003
23004    fn is_completion_trigger(
23005        &self,
23006        buffer: &Entity<Buffer>,
23007        position: language::Anchor,
23008        text: &str,
23009        trigger_in_words: bool,
23010        menu_is_open: bool,
23011        cx: &mut Context<Editor>,
23012    ) -> bool {
23013        let mut chars = text.chars();
23014        let char = if let Some(char) = chars.next() {
23015            char
23016        } else {
23017            return false;
23018        };
23019        if chars.next().is_some() {
23020            return false;
23021        }
23022
23023        let buffer = buffer.read(cx);
23024        let snapshot = buffer.snapshot();
23025        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23026            return false;
23027        }
23028        let classifier = snapshot
23029            .char_classifier_at(position)
23030            .scope_context(Some(CharScopeContext::Completion));
23031        if trigger_in_words && classifier.is_word(char) {
23032            return true;
23033        }
23034
23035        buffer.completion_triggers().contains(text)
23036    }
23037}
23038
23039impl SemanticsProvider for Entity<Project> {
23040    fn hover(
23041        &self,
23042        buffer: &Entity<Buffer>,
23043        position: text::Anchor,
23044        cx: &mut App,
23045    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23046        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23047    }
23048
23049    fn document_highlights(
23050        &self,
23051        buffer: &Entity<Buffer>,
23052        position: text::Anchor,
23053        cx: &mut App,
23054    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23055        Some(self.update(cx, |project, cx| {
23056            project.document_highlights(buffer, position, cx)
23057        }))
23058    }
23059
23060    fn definitions(
23061        &self,
23062        buffer: &Entity<Buffer>,
23063        position: text::Anchor,
23064        kind: GotoDefinitionKind,
23065        cx: &mut App,
23066    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23067        Some(self.update(cx, |project, cx| match kind {
23068            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23069            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23070            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23071            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23072        }))
23073    }
23074
23075    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23076        self.update(cx, |project, cx| {
23077            if project
23078                .active_debug_session(cx)
23079                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23080            {
23081                return true;
23082            }
23083
23084            buffer.update(cx, |buffer, cx| {
23085                project.any_language_server_supports_inlay_hints(buffer, cx)
23086            })
23087        })
23088    }
23089
23090    fn inline_values(
23091        &self,
23092        buffer_handle: Entity<Buffer>,
23093        range: Range<text::Anchor>,
23094        cx: &mut App,
23095    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23096        self.update(cx, |project, cx| {
23097            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23098
23099            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23100        })
23101    }
23102
23103    fn inlay_hints(
23104        &self,
23105        buffer_handle: Entity<Buffer>,
23106        range: Range<text::Anchor>,
23107        cx: &mut App,
23108    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23109        Some(self.update(cx, |project, cx| {
23110            project.inlay_hints(buffer_handle, range, cx)
23111        }))
23112    }
23113
23114    fn resolve_inlay_hint(
23115        &self,
23116        hint: InlayHint,
23117        buffer_handle: Entity<Buffer>,
23118        server_id: LanguageServerId,
23119        cx: &mut App,
23120    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23121        Some(self.update(cx, |project, cx| {
23122            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23123        }))
23124    }
23125
23126    fn range_for_rename(
23127        &self,
23128        buffer: &Entity<Buffer>,
23129        position: text::Anchor,
23130        cx: &mut App,
23131    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23132        Some(self.update(cx, |project, cx| {
23133            let buffer = buffer.clone();
23134            let task = project.prepare_rename(buffer.clone(), position, cx);
23135            cx.spawn(async move |_, cx| {
23136                Ok(match task.await? {
23137                    PrepareRenameResponse::Success(range) => Some(range),
23138                    PrepareRenameResponse::InvalidPosition => None,
23139                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23140                        // Fallback on using TreeSitter info to determine identifier range
23141                        buffer.read_with(cx, |buffer, _| {
23142                            let snapshot = buffer.snapshot();
23143                            let (range, kind) = snapshot.surrounding_word(position, None);
23144                            if kind != Some(CharKind::Word) {
23145                                return None;
23146                            }
23147                            Some(
23148                                snapshot.anchor_before(range.start)
23149                                    ..snapshot.anchor_after(range.end),
23150                            )
23151                        })?
23152                    }
23153                })
23154            })
23155        }))
23156    }
23157
23158    fn perform_rename(
23159        &self,
23160        buffer: &Entity<Buffer>,
23161        position: text::Anchor,
23162        new_name: String,
23163        cx: &mut App,
23164    ) -> Option<Task<Result<ProjectTransaction>>> {
23165        Some(self.update(cx, |project, cx| {
23166            project.perform_rename(buffer.clone(), position, new_name, cx)
23167        }))
23168    }
23169}
23170
23171fn inlay_hint_settings(
23172    location: Anchor,
23173    snapshot: &MultiBufferSnapshot,
23174    cx: &mut Context<Editor>,
23175) -> InlayHintSettings {
23176    let file = snapshot.file_at(location);
23177    let language = snapshot.language_at(location).map(|l| l.name());
23178    language_settings(language, file, cx).inlay_hints
23179}
23180
23181fn consume_contiguous_rows(
23182    contiguous_row_selections: &mut Vec<Selection<Point>>,
23183    selection: &Selection<Point>,
23184    display_map: &DisplaySnapshot,
23185    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23186) -> (MultiBufferRow, MultiBufferRow) {
23187    contiguous_row_selections.push(selection.clone());
23188    let start_row = starting_row(selection, display_map);
23189    let mut end_row = ending_row(selection, display_map);
23190
23191    while let Some(next_selection) = selections.peek() {
23192        if next_selection.start.row <= end_row.0 {
23193            end_row = ending_row(next_selection, display_map);
23194            contiguous_row_selections.push(selections.next().unwrap().clone());
23195        } else {
23196            break;
23197        }
23198    }
23199    (start_row, end_row)
23200}
23201
23202fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23203    if selection.start.column > 0 {
23204        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23205    } else {
23206        MultiBufferRow(selection.start.row)
23207    }
23208}
23209
23210fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23211    if next_selection.end.column > 0 || next_selection.is_empty() {
23212        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23213    } else {
23214        MultiBufferRow(next_selection.end.row)
23215    }
23216}
23217
23218impl EditorSnapshot {
23219    pub fn remote_selections_in_range<'a>(
23220        &'a self,
23221        range: &'a Range<Anchor>,
23222        collaboration_hub: &dyn CollaborationHub,
23223        cx: &'a App,
23224    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23225        let participant_names = collaboration_hub.user_names(cx);
23226        let participant_indices = collaboration_hub.user_participant_indices(cx);
23227        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23228        let collaborators_by_replica_id = collaborators_by_peer_id
23229            .values()
23230            .map(|collaborator| (collaborator.replica_id, collaborator))
23231            .collect::<HashMap<_, _>>();
23232        self.buffer_snapshot()
23233            .selections_in_range(range, false)
23234            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23235                if replica_id == AGENT_REPLICA_ID {
23236                    Some(RemoteSelection {
23237                        replica_id,
23238                        selection,
23239                        cursor_shape,
23240                        line_mode,
23241                        collaborator_id: CollaboratorId::Agent,
23242                        user_name: Some("Agent".into()),
23243                        color: cx.theme().players().agent(),
23244                    })
23245                } else {
23246                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23247                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23248                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23249                    Some(RemoteSelection {
23250                        replica_id,
23251                        selection,
23252                        cursor_shape,
23253                        line_mode,
23254                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23255                        user_name,
23256                        color: if let Some(index) = participant_index {
23257                            cx.theme().players().color_for_participant(index.0)
23258                        } else {
23259                            cx.theme().players().absent()
23260                        },
23261                    })
23262                }
23263            })
23264    }
23265
23266    pub fn hunks_for_ranges(
23267        &self,
23268        ranges: impl IntoIterator<Item = Range<Point>>,
23269    ) -> Vec<MultiBufferDiffHunk> {
23270        let mut hunks = Vec::new();
23271        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23272            HashMap::default();
23273        for query_range in ranges {
23274            let query_rows =
23275                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23276            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23277                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23278            ) {
23279                // Include deleted hunks that are adjacent to the query range, because
23280                // otherwise they would be missed.
23281                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23282                if hunk.status().is_deleted() {
23283                    intersects_range |= hunk.row_range.start == query_rows.end;
23284                    intersects_range |= hunk.row_range.end == query_rows.start;
23285                }
23286                if intersects_range {
23287                    if !processed_buffer_rows
23288                        .entry(hunk.buffer_id)
23289                        .or_default()
23290                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23291                    {
23292                        continue;
23293                    }
23294                    hunks.push(hunk);
23295                }
23296            }
23297        }
23298
23299        hunks
23300    }
23301
23302    fn display_diff_hunks_for_rows<'a>(
23303        &'a self,
23304        display_rows: Range<DisplayRow>,
23305        folded_buffers: &'a HashSet<BufferId>,
23306    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23307        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23308        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23309
23310        self.buffer_snapshot()
23311            .diff_hunks_in_range(buffer_start..buffer_end)
23312            .filter_map(|hunk| {
23313                if folded_buffers.contains(&hunk.buffer_id) {
23314                    return None;
23315                }
23316
23317                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23318                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23319
23320                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23321                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23322
23323                let display_hunk = if hunk_display_start.column() != 0 {
23324                    DisplayDiffHunk::Folded {
23325                        display_row: hunk_display_start.row(),
23326                    }
23327                } else {
23328                    let mut end_row = hunk_display_end.row();
23329                    if hunk_display_end.column() > 0 {
23330                        end_row.0 += 1;
23331                    }
23332                    let is_created_file = hunk.is_created_file();
23333                    DisplayDiffHunk::Unfolded {
23334                        status: hunk.status(),
23335                        diff_base_byte_range: hunk.diff_base_byte_range,
23336                        display_row_range: hunk_display_start.row()..end_row,
23337                        multi_buffer_range: Anchor::range_in_buffer(
23338                            hunk.excerpt_id,
23339                            hunk.buffer_id,
23340                            hunk.buffer_range,
23341                        ),
23342                        is_created_file,
23343                    }
23344                };
23345
23346                Some(display_hunk)
23347            })
23348    }
23349
23350    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23351        self.display_snapshot
23352            .buffer_snapshot()
23353            .language_at(position)
23354    }
23355
23356    pub fn is_focused(&self) -> bool {
23357        self.is_focused
23358    }
23359
23360    pub fn placeholder_text(&self) -> Option<String> {
23361        self.placeholder_display_snapshot
23362            .as_ref()
23363            .map(|display_map| display_map.text())
23364    }
23365
23366    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23367        self.scroll_anchor.scroll_position(&self.display_snapshot)
23368    }
23369
23370    fn gutter_dimensions(
23371        &self,
23372        font_id: FontId,
23373        font_size: Pixels,
23374        max_line_number_width: Pixels,
23375        cx: &App,
23376    ) -> Option<GutterDimensions> {
23377        if !self.show_gutter {
23378            return None;
23379        }
23380
23381        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23382        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23383
23384        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23385            matches!(
23386                ProjectSettings::get_global(cx).git.git_gutter,
23387                GitGutterSetting::TrackedFiles
23388            )
23389        });
23390        let gutter_settings = EditorSettings::get_global(cx).gutter;
23391        let show_line_numbers = self
23392            .show_line_numbers
23393            .unwrap_or(gutter_settings.line_numbers);
23394        let line_gutter_width = if show_line_numbers {
23395            // Avoid flicker-like gutter resizes when the line number gains another digit by
23396            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23397            let min_width_for_number_on_gutter =
23398                ch_advance * gutter_settings.min_line_number_digits as f32;
23399            max_line_number_width.max(min_width_for_number_on_gutter)
23400        } else {
23401            0.0.into()
23402        };
23403
23404        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23405        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23406
23407        let git_blame_entries_width =
23408            self.git_blame_gutter_max_author_length
23409                .map(|max_author_length| {
23410                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23411                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23412
23413                    /// The number of characters to dedicate to gaps and margins.
23414                    const SPACING_WIDTH: usize = 4;
23415
23416                    let max_char_count = max_author_length.min(renderer.max_author_length())
23417                        + ::git::SHORT_SHA_LENGTH
23418                        + MAX_RELATIVE_TIMESTAMP.len()
23419                        + SPACING_WIDTH;
23420
23421                    ch_advance * max_char_count
23422                });
23423
23424        let is_singleton = self.buffer_snapshot().is_singleton();
23425
23426        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23427        left_padding += if !is_singleton {
23428            ch_width * 4.0
23429        } else if show_runnables || show_breakpoints {
23430            ch_width * 3.0
23431        } else if show_git_gutter && show_line_numbers {
23432            ch_width * 2.0
23433        } else if show_git_gutter || show_line_numbers {
23434            ch_width
23435        } else {
23436            px(0.)
23437        };
23438
23439        let shows_folds = is_singleton && gutter_settings.folds;
23440
23441        let right_padding = if shows_folds && show_line_numbers {
23442            ch_width * 4.0
23443        } else if shows_folds || (!is_singleton && show_line_numbers) {
23444            ch_width * 3.0
23445        } else if show_line_numbers {
23446            ch_width
23447        } else {
23448            px(0.)
23449        };
23450
23451        Some(GutterDimensions {
23452            left_padding,
23453            right_padding,
23454            width: line_gutter_width + left_padding + right_padding,
23455            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23456            git_blame_entries_width,
23457        })
23458    }
23459
23460    pub fn render_crease_toggle(
23461        &self,
23462        buffer_row: MultiBufferRow,
23463        row_contains_cursor: bool,
23464        editor: Entity<Editor>,
23465        window: &mut Window,
23466        cx: &mut App,
23467    ) -> Option<AnyElement> {
23468        let folded = self.is_line_folded(buffer_row);
23469        let mut is_foldable = false;
23470
23471        if let Some(crease) = self
23472            .crease_snapshot
23473            .query_row(buffer_row, self.buffer_snapshot())
23474        {
23475            is_foldable = true;
23476            match crease {
23477                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23478                    if let Some(render_toggle) = render_toggle {
23479                        let toggle_callback =
23480                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23481                                if folded {
23482                                    editor.update(cx, |editor, cx| {
23483                                        editor.fold_at(buffer_row, window, cx)
23484                                    });
23485                                } else {
23486                                    editor.update(cx, |editor, cx| {
23487                                        editor.unfold_at(buffer_row, window, cx)
23488                                    });
23489                                }
23490                            });
23491                        return Some((render_toggle)(
23492                            buffer_row,
23493                            folded,
23494                            toggle_callback,
23495                            window,
23496                            cx,
23497                        ));
23498                    }
23499                }
23500            }
23501        }
23502
23503        is_foldable |= self.starts_indent(buffer_row);
23504
23505        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23506            Some(
23507                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23508                    .toggle_state(folded)
23509                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23510                        if folded {
23511                            this.unfold_at(buffer_row, window, cx);
23512                        } else {
23513                            this.fold_at(buffer_row, window, cx);
23514                        }
23515                    }))
23516                    .into_any_element(),
23517            )
23518        } else {
23519            None
23520        }
23521    }
23522
23523    pub fn render_crease_trailer(
23524        &self,
23525        buffer_row: MultiBufferRow,
23526        window: &mut Window,
23527        cx: &mut App,
23528    ) -> Option<AnyElement> {
23529        let folded = self.is_line_folded(buffer_row);
23530        if let Crease::Inline { render_trailer, .. } = self
23531            .crease_snapshot
23532            .query_row(buffer_row, self.buffer_snapshot())?
23533        {
23534            let render_trailer = render_trailer.as_ref()?;
23535            Some(render_trailer(buffer_row, folded, window, cx))
23536        } else {
23537            None
23538        }
23539    }
23540}
23541
23542impl Deref for EditorSnapshot {
23543    type Target = DisplaySnapshot;
23544
23545    fn deref(&self) -> &Self::Target {
23546        &self.display_snapshot
23547    }
23548}
23549
23550#[derive(Clone, Debug, PartialEq, Eq)]
23551pub enum EditorEvent {
23552    InputIgnored {
23553        text: Arc<str>,
23554    },
23555    InputHandled {
23556        utf16_range_to_replace: Option<Range<isize>>,
23557        text: Arc<str>,
23558    },
23559    ExcerptsAdded {
23560        buffer: Entity<Buffer>,
23561        predecessor: ExcerptId,
23562        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23563    },
23564    ExcerptsRemoved {
23565        ids: Vec<ExcerptId>,
23566        removed_buffer_ids: Vec<BufferId>,
23567    },
23568    BufferFoldToggled {
23569        ids: Vec<ExcerptId>,
23570        folded: bool,
23571    },
23572    ExcerptsEdited {
23573        ids: Vec<ExcerptId>,
23574    },
23575    ExcerptsExpanded {
23576        ids: Vec<ExcerptId>,
23577    },
23578    BufferEdited,
23579    Edited {
23580        transaction_id: clock::Lamport,
23581    },
23582    Reparsed(BufferId),
23583    Focused,
23584    FocusedIn,
23585    Blurred,
23586    DirtyChanged,
23587    Saved,
23588    TitleChanged,
23589    SelectionsChanged {
23590        local: bool,
23591    },
23592    ScrollPositionChanged {
23593        local: bool,
23594        autoscroll: bool,
23595    },
23596    TransactionUndone {
23597        transaction_id: clock::Lamport,
23598    },
23599    TransactionBegun {
23600        transaction_id: clock::Lamport,
23601    },
23602    CursorShapeChanged,
23603    BreadcrumbsChanged,
23604    PushedToNavHistory {
23605        anchor: Anchor,
23606        is_deactivate: bool,
23607    },
23608}
23609
23610impl EventEmitter<EditorEvent> for Editor {}
23611
23612impl Focusable for Editor {
23613    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23614        self.focus_handle.clone()
23615    }
23616}
23617
23618impl Render for Editor {
23619    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23620        let settings = ThemeSettings::get_global(cx);
23621
23622        let mut text_style = match self.mode {
23623            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23624                color: cx.theme().colors().editor_foreground,
23625                font_family: settings.ui_font.family.clone(),
23626                font_features: settings.ui_font.features.clone(),
23627                font_fallbacks: settings.ui_font.fallbacks.clone(),
23628                font_size: rems(0.875).into(),
23629                font_weight: settings.ui_font.weight,
23630                line_height: relative(settings.buffer_line_height.value()),
23631                ..Default::default()
23632            },
23633            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23634                color: cx.theme().colors().editor_foreground,
23635                font_family: settings.buffer_font.family.clone(),
23636                font_features: settings.buffer_font.features.clone(),
23637                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23638                font_size: settings.buffer_font_size(cx).into(),
23639                font_weight: settings.buffer_font.weight,
23640                line_height: relative(settings.buffer_line_height.value()),
23641                ..Default::default()
23642            },
23643        };
23644        if let Some(text_style_refinement) = &self.text_style_refinement {
23645            text_style.refine(text_style_refinement)
23646        }
23647
23648        let background = match self.mode {
23649            EditorMode::SingleLine => cx.theme().system().transparent,
23650            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23651            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23652            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23653        };
23654
23655        EditorElement::new(
23656            &cx.entity(),
23657            EditorStyle {
23658                background,
23659                border: cx.theme().colors().border,
23660                local_player: cx.theme().players().local(),
23661                text: text_style,
23662                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23663                syntax: cx.theme().syntax().clone(),
23664                status: cx.theme().status().clone(),
23665                inlay_hints_style: make_inlay_hints_style(cx),
23666                edit_prediction_styles: make_suggestion_styles(cx),
23667                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23668                show_underlines: self.diagnostics_enabled(),
23669            },
23670        )
23671    }
23672}
23673
23674impl EntityInputHandler for Editor {
23675    fn text_for_range(
23676        &mut self,
23677        range_utf16: Range<usize>,
23678        adjusted_range: &mut Option<Range<usize>>,
23679        _: &mut Window,
23680        cx: &mut Context<Self>,
23681    ) -> Option<String> {
23682        let snapshot = self.buffer.read(cx).read(cx);
23683        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23684        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23685        if (start.0..end.0) != range_utf16 {
23686            adjusted_range.replace(start.0..end.0);
23687        }
23688        Some(snapshot.text_for_range(start..end).collect())
23689    }
23690
23691    fn selected_text_range(
23692        &mut self,
23693        ignore_disabled_input: bool,
23694        _: &mut Window,
23695        cx: &mut Context<Self>,
23696    ) -> Option<UTF16Selection> {
23697        // Prevent the IME menu from appearing when holding down an alphabetic key
23698        // while input is disabled.
23699        if !ignore_disabled_input && !self.input_enabled {
23700            return None;
23701        }
23702
23703        let selection = self.selections.newest::<OffsetUtf16>(cx);
23704        let range = selection.range();
23705
23706        Some(UTF16Selection {
23707            range: range.start.0..range.end.0,
23708            reversed: selection.reversed,
23709        })
23710    }
23711
23712    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23713        let snapshot = self.buffer.read(cx).read(cx);
23714        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23715        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23716    }
23717
23718    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23719        self.clear_highlights::<InputComposition>(cx);
23720        self.ime_transaction.take();
23721    }
23722
23723    fn replace_text_in_range(
23724        &mut self,
23725        range_utf16: Option<Range<usize>>,
23726        text: &str,
23727        window: &mut Window,
23728        cx: &mut Context<Self>,
23729    ) {
23730        if !self.input_enabled {
23731            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23732            return;
23733        }
23734
23735        self.transact(window, cx, |this, window, cx| {
23736            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23737                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23738                Some(this.selection_replacement_ranges(range_utf16, cx))
23739            } else {
23740                this.marked_text_ranges(cx)
23741            };
23742
23743            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23744                let newest_selection_id = this.selections.newest_anchor().id;
23745                this.selections
23746                    .all::<OffsetUtf16>(cx)
23747                    .iter()
23748                    .zip(ranges_to_replace.iter())
23749                    .find_map(|(selection, range)| {
23750                        if selection.id == newest_selection_id {
23751                            Some(
23752                                (range.start.0 as isize - selection.head().0 as isize)
23753                                    ..(range.end.0 as isize - selection.head().0 as isize),
23754                            )
23755                        } else {
23756                            None
23757                        }
23758                    })
23759            });
23760
23761            cx.emit(EditorEvent::InputHandled {
23762                utf16_range_to_replace: range_to_replace,
23763                text: text.into(),
23764            });
23765
23766            if let Some(new_selected_ranges) = new_selected_ranges {
23767                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23768                    selections.select_ranges(new_selected_ranges)
23769                });
23770                this.backspace(&Default::default(), window, cx);
23771            }
23772
23773            this.handle_input(text, window, cx);
23774        });
23775
23776        if let Some(transaction) = self.ime_transaction {
23777            self.buffer.update(cx, |buffer, cx| {
23778                buffer.group_until_transaction(transaction, cx);
23779            });
23780        }
23781
23782        self.unmark_text(window, cx);
23783    }
23784
23785    fn replace_and_mark_text_in_range(
23786        &mut self,
23787        range_utf16: Option<Range<usize>>,
23788        text: &str,
23789        new_selected_range_utf16: Option<Range<usize>>,
23790        window: &mut Window,
23791        cx: &mut Context<Self>,
23792    ) {
23793        if !self.input_enabled {
23794            return;
23795        }
23796
23797        let transaction = self.transact(window, cx, |this, window, cx| {
23798            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23799                let snapshot = this.buffer.read(cx).read(cx);
23800                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23801                    for marked_range in &mut marked_ranges {
23802                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23803                        marked_range.start.0 += relative_range_utf16.start;
23804                        marked_range.start =
23805                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23806                        marked_range.end =
23807                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23808                    }
23809                }
23810                Some(marked_ranges)
23811            } else if let Some(range_utf16) = range_utf16 {
23812                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23813                Some(this.selection_replacement_ranges(range_utf16, cx))
23814            } else {
23815                None
23816            };
23817
23818            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23819                let newest_selection_id = this.selections.newest_anchor().id;
23820                this.selections
23821                    .all::<OffsetUtf16>(cx)
23822                    .iter()
23823                    .zip(ranges_to_replace.iter())
23824                    .find_map(|(selection, range)| {
23825                        if selection.id == newest_selection_id {
23826                            Some(
23827                                (range.start.0 as isize - selection.head().0 as isize)
23828                                    ..(range.end.0 as isize - selection.head().0 as isize),
23829                            )
23830                        } else {
23831                            None
23832                        }
23833                    })
23834            });
23835
23836            cx.emit(EditorEvent::InputHandled {
23837                utf16_range_to_replace: range_to_replace,
23838                text: text.into(),
23839            });
23840
23841            if let Some(ranges) = ranges_to_replace {
23842                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23843                    s.select_ranges(ranges)
23844                });
23845            }
23846
23847            let marked_ranges = {
23848                let snapshot = this.buffer.read(cx).read(cx);
23849                this.selections
23850                    .disjoint_anchors_arc()
23851                    .iter()
23852                    .map(|selection| {
23853                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23854                    })
23855                    .collect::<Vec<_>>()
23856            };
23857
23858            if text.is_empty() {
23859                this.unmark_text(window, cx);
23860            } else {
23861                this.highlight_text::<InputComposition>(
23862                    marked_ranges.clone(),
23863                    HighlightStyle {
23864                        underline: Some(UnderlineStyle {
23865                            thickness: px(1.),
23866                            color: None,
23867                            wavy: false,
23868                        }),
23869                        ..Default::default()
23870                    },
23871                    cx,
23872                );
23873            }
23874
23875            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23876            let use_autoclose = this.use_autoclose;
23877            let use_auto_surround = this.use_auto_surround;
23878            this.set_use_autoclose(false);
23879            this.set_use_auto_surround(false);
23880            this.handle_input(text, window, cx);
23881            this.set_use_autoclose(use_autoclose);
23882            this.set_use_auto_surround(use_auto_surround);
23883
23884            if let Some(new_selected_range) = new_selected_range_utf16 {
23885                let snapshot = this.buffer.read(cx).read(cx);
23886                let new_selected_ranges = marked_ranges
23887                    .into_iter()
23888                    .map(|marked_range| {
23889                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23890                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23891                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23892                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23893                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23894                    })
23895                    .collect::<Vec<_>>();
23896
23897                drop(snapshot);
23898                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23899                    selections.select_ranges(new_selected_ranges)
23900                });
23901            }
23902        });
23903
23904        self.ime_transaction = self.ime_transaction.or(transaction);
23905        if let Some(transaction) = self.ime_transaction {
23906            self.buffer.update(cx, |buffer, cx| {
23907                buffer.group_until_transaction(transaction, cx);
23908            });
23909        }
23910
23911        if self.text_highlights::<InputComposition>(cx).is_none() {
23912            self.ime_transaction.take();
23913        }
23914    }
23915
23916    fn bounds_for_range(
23917        &mut self,
23918        range_utf16: Range<usize>,
23919        element_bounds: gpui::Bounds<Pixels>,
23920        window: &mut Window,
23921        cx: &mut Context<Self>,
23922    ) -> Option<gpui::Bounds<Pixels>> {
23923        let text_layout_details = self.text_layout_details(window);
23924        let CharacterDimensions {
23925            em_width,
23926            em_advance,
23927            line_height,
23928        } = self.character_dimensions(window);
23929
23930        let snapshot = self.snapshot(window, cx);
23931        let scroll_position = snapshot.scroll_position();
23932        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
23933
23934        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23935        let x = Pixels::from(
23936            ScrollOffset::from(
23937                snapshot.x_for_display_point(start, &text_layout_details)
23938                    + self.gutter_dimensions.full_width(),
23939            ) - scroll_left,
23940        );
23941        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
23942
23943        Some(Bounds {
23944            origin: element_bounds.origin + point(x, y),
23945            size: size(em_width, line_height),
23946        })
23947    }
23948
23949    fn character_index_for_point(
23950        &mut self,
23951        point: gpui::Point<Pixels>,
23952        _window: &mut Window,
23953        _cx: &mut Context<Self>,
23954    ) -> Option<usize> {
23955        let position_map = self.last_position_map.as_ref()?;
23956        if !position_map.text_hitbox.contains(&point) {
23957            return None;
23958        }
23959        let display_point = position_map.point_for_position(point).previous_valid;
23960        let anchor = position_map
23961            .snapshot
23962            .display_point_to_anchor(display_point, Bias::Left);
23963        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
23964        Some(utf16_offset.0)
23965    }
23966}
23967
23968trait SelectionExt {
23969    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23970    fn spanned_rows(
23971        &self,
23972        include_end_if_at_line_start: bool,
23973        map: &DisplaySnapshot,
23974    ) -> Range<MultiBufferRow>;
23975}
23976
23977impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23978    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23979        let start = self
23980            .start
23981            .to_point(map.buffer_snapshot())
23982            .to_display_point(map);
23983        let end = self
23984            .end
23985            .to_point(map.buffer_snapshot())
23986            .to_display_point(map);
23987        if self.reversed {
23988            end..start
23989        } else {
23990            start..end
23991        }
23992    }
23993
23994    fn spanned_rows(
23995        &self,
23996        include_end_if_at_line_start: bool,
23997        map: &DisplaySnapshot,
23998    ) -> Range<MultiBufferRow> {
23999        let start = self.start.to_point(map.buffer_snapshot());
24000        let mut end = self.end.to_point(map.buffer_snapshot());
24001        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24002            end.row -= 1;
24003        }
24004
24005        let buffer_start = map.prev_line_boundary(start).0;
24006        let buffer_end = map.next_line_boundary(end).0;
24007        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24008    }
24009}
24010
24011impl<T: InvalidationRegion> InvalidationStack<T> {
24012    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24013    where
24014        S: Clone + ToOffset,
24015    {
24016        while let Some(region) = self.last() {
24017            let all_selections_inside_invalidation_ranges =
24018                if selections.len() == region.ranges().len() {
24019                    selections
24020                        .iter()
24021                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24022                        .all(|(selection, invalidation_range)| {
24023                            let head = selection.head().to_offset(buffer);
24024                            invalidation_range.start <= head && invalidation_range.end >= head
24025                        })
24026                } else {
24027                    false
24028                };
24029
24030            if all_selections_inside_invalidation_ranges {
24031                break;
24032            } else {
24033                self.pop();
24034            }
24035        }
24036    }
24037}
24038
24039impl<T> Default for InvalidationStack<T> {
24040    fn default() -> Self {
24041        Self(Default::default())
24042    }
24043}
24044
24045impl<T> Deref for InvalidationStack<T> {
24046    type Target = Vec<T>;
24047
24048    fn deref(&self) -> &Self::Target {
24049        &self.0
24050    }
24051}
24052
24053impl<T> DerefMut for InvalidationStack<T> {
24054    fn deref_mut(&mut self) -> &mut Self::Target {
24055        &mut self.0
24056    }
24057}
24058
24059impl InvalidationRegion for SnippetState {
24060    fn ranges(&self) -> &[Range<Anchor>] {
24061        &self.ranges[self.active_index]
24062    }
24063}
24064
24065fn edit_prediction_edit_text(
24066    current_snapshot: &BufferSnapshot,
24067    edits: &[(Range<Anchor>, String)],
24068    edit_preview: &EditPreview,
24069    include_deletions: bool,
24070    cx: &App,
24071) -> HighlightedText {
24072    let edits = edits
24073        .iter()
24074        .map(|(anchor, text)| {
24075            (
24076                anchor.start.text_anchor..anchor.end.text_anchor,
24077                text.clone(),
24078            )
24079        })
24080        .collect::<Vec<_>>();
24081
24082    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24083}
24084
24085fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24086    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24087    // Just show the raw edit text with basic styling
24088    let mut text = String::new();
24089    let mut highlights = Vec::new();
24090
24091    let insertion_highlight_style = HighlightStyle {
24092        color: Some(cx.theme().colors().text),
24093        ..Default::default()
24094    };
24095
24096    for (_, edit_text) in edits {
24097        let start_offset = text.len();
24098        text.push_str(edit_text);
24099        let end_offset = text.len();
24100
24101        if start_offset < end_offset {
24102            highlights.push((start_offset..end_offset, insertion_highlight_style));
24103        }
24104    }
24105
24106    HighlightedText {
24107        text: text.into(),
24108        highlights,
24109    }
24110}
24111
24112pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24113    match severity {
24114        lsp::DiagnosticSeverity::ERROR => colors.error,
24115        lsp::DiagnosticSeverity::WARNING => colors.warning,
24116        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24117        lsp::DiagnosticSeverity::HINT => colors.info,
24118        _ => colors.ignored,
24119    }
24120}
24121
24122pub fn styled_runs_for_code_label<'a>(
24123    label: &'a CodeLabel,
24124    syntax_theme: &'a theme::SyntaxTheme,
24125) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24126    let fade_out = HighlightStyle {
24127        fade_out: Some(0.35),
24128        ..Default::default()
24129    };
24130
24131    let mut prev_end = label.filter_range.end;
24132    label
24133        .runs
24134        .iter()
24135        .enumerate()
24136        .flat_map(move |(ix, (range, highlight_id))| {
24137            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24138                style
24139            } else {
24140                return Default::default();
24141            };
24142            let muted_style = style.highlight(fade_out);
24143
24144            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24145            if range.start >= label.filter_range.end {
24146                if range.start > prev_end {
24147                    runs.push((prev_end..range.start, fade_out));
24148                }
24149                runs.push((range.clone(), muted_style));
24150            } else if range.end <= label.filter_range.end {
24151                runs.push((range.clone(), style));
24152            } else {
24153                runs.push((range.start..label.filter_range.end, style));
24154                runs.push((label.filter_range.end..range.end, muted_style));
24155            }
24156            prev_end = cmp::max(prev_end, range.end);
24157
24158            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24159                runs.push((prev_end..label.text.len(), fade_out));
24160            }
24161
24162            runs
24163        })
24164}
24165
24166pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24167    let mut prev_index = 0;
24168    let mut prev_codepoint: Option<char> = None;
24169    text.char_indices()
24170        .chain([(text.len(), '\0')])
24171        .filter_map(move |(index, codepoint)| {
24172            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24173            let is_boundary = index == text.len()
24174                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24175                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24176            if is_boundary {
24177                let chunk = &text[prev_index..index];
24178                prev_index = index;
24179                Some(chunk)
24180            } else {
24181                None
24182            }
24183        })
24184}
24185
24186pub trait RangeToAnchorExt: Sized {
24187    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24188
24189    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24190        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24191        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24192    }
24193}
24194
24195impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24196    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24197        let start_offset = self.start.to_offset(snapshot);
24198        let end_offset = self.end.to_offset(snapshot);
24199        if start_offset == end_offset {
24200            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24201        } else {
24202            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24203        }
24204    }
24205}
24206
24207pub trait RowExt {
24208    fn as_f64(&self) -> f64;
24209
24210    fn next_row(&self) -> Self;
24211
24212    fn previous_row(&self) -> Self;
24213
24214    fn minus(&self, other: Self) -> u32;
24215}
24216
24217impl RowExt for DisplayRow {
24218    fn as_f64(&self) -> f64 {
24219        self.0 as _
24220    }
24221
24222    fn next_row(&self) -> Self {
24223        Self(self.0 + 1)
24224    }
24225
24226    fn previous_row(&self) -> Self {
24227        Self(self.0.saturating_sub(1))
24228    }
24229
24230    fn minus(&self, other: Self) -> u32 {
24231        self.0 - other.0
24232    }
24233}
24234
24235impl RowExt for MultiBufferRow {
24236    fn as_f64(&self) -> f64 {
24237        self.0 as _
24238    }
24239
24240    fn next_row(&self) -> Self {
24241        Self(self.0 + 1)
24242    }
24243
24244    fn previous_row(&self) -> Self {
24245        Self(self.0.saturating_sub(1))
24246    }
24247
24248    fn minus(&self, other: Self) -> u32 {
24249        self.0 - other.0
24250    }
24251}
24252
24253trait RowRangeExt {
24254    type Row;
24255
24256    fn len(&self) -> usize;
24257
24258    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24259}
24260
24261impl RowRangeExt for Range<MultiBufferRow> {
24262    type Row = MultiBufferRow;
24263
24264    fn len(&self) -> usize {
24265        (self.end.0 - self.start.0) as usize
24266    }
24267
24268    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24269        (self.start.0..self.end.0).map(MultiBufferRow)
24270    }
24271}
24272
24273impl RowRangeExt for Range<DisplayRow> {
24274    type Row = DisplayRow;
24275
24276    fn len(&self) -> usize {
24277        (self.end.0 - self.start.0) as usize
24278    }
24279
24280    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24281        (self.start.0..self.end.0).map(DisplayRow)
24282    }
24283}
24284
24285/// If select range has more than one line, we
24286/// just point the cursor to range.start.
24287fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24288    if range.start.row == range.end.row {
24289        range
24290    } else {
24291        range.start..range.start
24292    }
24293}
24294pub struct KillRing(ClipboardItem);
24295impl Global for KillRing {}
24296
24297const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24298
24299enum BreakpointPromptEditAction {
24300    Log,
24301    Condition,
24302    HitCondition,
24303}
24304
24305struct BreakpointPromptEditor {
24306    pub(crate) prompt: Entity<Editor>,
24307    editor: WeakEntity<Editor>,
24308    breakpoint_anchor: Anchor,
24309    breakpoint: Breakpoint,
24310    edit_action: BreakpointPromptEditAction,
24311    block_ids: HashSet<CustomBlockId>,
24312    editor_margins: Arc<Mutex<EditorMargins>>,
24313    _subscriptions: Vec<Subscription>,
24314}
24315
24316impl BreakpointPromptEditor {
24317    const MAX_LINES: u8 = 4;
24318
24319    fn new(
24320        editor: WeakEntity<Editor>,
24321        breakpoint_anchor: Anchor,
24322        breakpoint: Breakpoint,
24323        edit_action: BreakpointPromptEditAction,
24324        window: &mut Window,
24325        cx: &mut Context<Self>,
24326    ) -> Self {
24327        let base_text = match edit_action {
24328            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24329            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24330            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24331        }
24332        .map(|msg| msg.to_string())
24333        .unwrap_or_default();
24334
24335        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24336        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24337
24338        let prompt = cx.new(|cx| {
24339            let mut prompt = Editor::new(
24340                EditorMode::AutoHeight {
24341                    min_lines: 1,
24342                    max_lines: Some(Self::MAX_LINES as usize),
24343                },
24344                buffer,
24345                None,
24346                window,
24347                cx,
24348            );
24349            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24350            prompt.set_show_cursor_when_unfocused(false, cx);
24351            prompt.set_placeholder_text(
24352                match edit_action {
24353                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24354                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24355                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24356                },
24357                window,
24358                cx,
24359            );
24360
24361            prompt
24362        });
24363
24364        Self {
24365            prompt,
24366            editor,
24367            breakpoint_anchor,
24368            breakpoint,
24369            edit_action,
24370            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24371            block_ids: Default::default(),
24372            _subscriptions: vec![],
24373        }
24374    }
24375
24376    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24377        self.block_ids.extend(block_ids)
24378    }
24379
24380    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24381        if let Some(editor) = self.editor.upgrade() {
24382            let message = self
24383                .prompt
24384                .read(cx)
24385                .buffer
24386                .read(cx)
24387                .as_singleton()
24388                .expect("A multi buffer in breakpoint prompt isn't possible")
24389                .read(cx)
24390                .as_rope()
24391                .to_string();
24392
24393            editor.update(cx, |editor, cx| {
24394                editor.edit_breakpoint_at_anchor(
24395                    self.breakpoint_anchor,
24396                    self.breakpoint.clone(),
24397                    match self.edit_action {
24398                        BreakpointPromptEditAction::Log => {
24399                            BreakpointEditAction::EditLogMessage(message.into())
24400                        }
24401                        BreakpointPromptEditAction::Condition => {
24402                            BreakpointEditAction::EditCondition(message.into())
24403                        }
24404                        BreakpointPromptEditAction::HitCondition => {
24405                            BreakpointEditAction::EditHitCondition(message.into())
24406                        }
24407                    },
24408                    cx,
24409                );
24410
24411                editor.remove_blocks(self.block_ids.clone(), None, cx);
24412                cx.focus_self(window);
24413            });
24414        }
24415    }
24416
24417    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24418        self.editor
24419            .update(cx, |editor, cx| {
24420                editor.remove_blocks(self.block_ids.clone(), None, cx);
24421                window.focus(&editor.focus_handle);
24422            })
24423            .log_err();
24424    }
24425
24426    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24427        let settings = ThemeSettings::get_global(cx);
24428        let text_style = TextStyle {
24429            color: if self.prompt.read(cx).read_only(cx) {
24430                cx.theme().colors().text_disabled
24431            } else {
24432                cx.theme().colors().text
24433            },
24434            font_family: settings.buffer_font.family.clone(),
24435            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24436            font_size: settings.buffer_font_size(cx).into(),
24437            font_weight: settings.buffer_font.weight,
24438            line_height: relative(settings.buffer_line_height.value()),
24439            ..Default::default()
24440        };
24441        EditorElement::new(
24442            &self.prompt,
24443            EditorStyle {
24444                background: cx.theme().colors().editor_background,
24445                local_player: cx.theme().players().local(),
24446                text: text_style,
24447                ..Default::default()
24448            },
24449        )
24450    }
24451}
24452
24453impl Render for BreakpointPromptEditor {
24454    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24455        let editor_margins = *self.editor_margins.lock();
24456        let gutter_dimensions = editor_margins.gutter;
24457        h_flex()
24458            .key_context("Editor")
24459            .bg(cx.theme().colors().editor_background)
24460            .border_y_1()
24461            .border_color(cx.theme().status().info_border)
24462            .size_full()
24463            .py(window.line_height() / 2.5)
24464            .on_action(cx.listener(Self::confirm))
24465            .on_action(cx.listener(Self::cancel))
24466            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24467            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24468    }
24469}
24470
24471impl Focusable for BreakpointPromptEditor {
24472    fn focus_handle(&self, cx: &App) -> FocusHandle {
24473        self.prompt.focus_handle(cx)
24474    }
24475}
24476
24477fn all_edits_insertions_or_deletions(
24478    edits: &Vec<(Range<Anchor>, String)>,
24479    snapshot: &MultiBufferSnapshot,
24480) -> bool {
24481    let mut all_insertions = true;
24482    let mut all_deletions = true;
24483
24484    for (range, new_text) in edits.iter() {
24485        let range_is_empty = range.to_offset(snapshot).is_empty();
24486        let text_is_empty = new_text.is_empty();
24487
24488        if range_is_empty != text_is_empty {
24489            if range_is_empty {
24490                all_deletions = false;
24491            } else {
24492                all_insertions = false;
24493            }
24494        } else {
24495            return false;
24496        }
24497
24498        if !all_insertions && !all_deletions {
24499            return false;
24500        }
24501    }
24502    all_insertions || all_deletions
24503}
24504
24505struct MissingEditPredictionKeybindingTooltip;
24506
24507impl Render for MissingEditPredictionKeybindingTooltip {
24508    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24509        ui::tooltip_container(cx, |container, cx| {
24510            container
24511                .flex_shrink_0()
24512                .max_w_80()
24513                .min_h(rems_from_px(124.))
24514                .justify_between()
24515                .child(
24516                    v_flex()
24517                        .flex_1()
24518                        .text_ui_sm(cx)
24519                        .child(Label::new("Conflict with Accept Keybinding"))
24520                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24521                )
24522                .child(
24523                    h_flex()
24524                        .pb_1()
24525                        .gap_1()
24526                        .items_end()
24527                        .w_full()
24528                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24529                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24530                        }))
24531                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24532                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24533                        })),
24534                )
24535        })
24536    }
24537}
24538
24539#[derive(Debug, Clone, Copy, PartialEq)]
24540pub struct LineHighlight {
24541    pub background: Background,
24542    pub border: Option<gpui::Hsla>,
24543    pub include_gutter: bool,
24544    pub type_id: Option<TypeId>,
24545}
24546
24547struct LineManipulationResult {
24548    pub new_text: String,
24549    pub line_count_before: usize,
24550    pub line_count_after: usize,
24551}
24552
24553fn render_diff_hunk_controls(
24554    row: u32,
24555    status: &DiffHunkStatus,
24556    hunk_range: Range<Anchor>,
24557    is_created_file: bool,
24558    line_height: Pixels,
24559    editor: &Entity<Editor>,
24560    _window: &mut Window,
24561    cx: &mut App,
24562) -> AnyElement {
24563    h_flex()
24564        .h(line_height)
24565        .mr_1()
24566        .gap_1()
24567        .px_0p5()
24568        .pb_1()
24569        .border_x_1()
24570        .border_b_1()
24571        .border_color(cx.theme().colors().border_variant)
24572        .rounded_b_lg()
24573        .bg(cx.theme().colors().editor_background)
24574        .gap_1()
24575        .block_mouse_except_scroll()
24576        .shadow_md()
24577        .child(if status.has_secondary_hunk() {
24578            Button::new(("stage", row as u64), "Stage")
24579                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24580                .tooltip({
24581                    let focus_handle = editor.focus_handle(cx);
24582                    move |window, cx| {
24583                        Tooltip::for_action_in(
24584                            "Stage Hunk",
24585                            &::git::ToggleStaged,
24586                            &focus_handle,
24587                            window,
24588                            cx,
24589                        )
24590                    }
24591                })
24592                .on_click({
24593                    let editor = editor.clone();
24594                    move |_event, _window, cx| {
24595                        editor.update(cx, |editor, cx| {
24596                            editor.stage_or_unstage_diff_hunks(
24597                                true,
24598                                vec![hunk_range.start..hunk_range.start],
24599                                cx,
24600                            );
24601                        });
24602                    }
24603                })
24604        } else {
24605            Button::new(("unstage", row as u64), "Unstage")
24606                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24607                .tooltip({
24608                    let focus_handle = editor.focus_handle(cx);
24609                    move |window, cx| {
24610                        Tooltip::for_action_in(
24611                            "Unstage Hunk",
24612                            &::git::ToggleStaged,
24613                            &focus_handle,
24614                            window,
24615                            cx,
24616                        )
24617                    }
24618                })
24619                .on_click({
24620                    let editor = editor.clone();
24621                    move |_event, _window, cx| {
24622                        editor.update(cx, |editor, cx| {
24623                            editor.stage_or_unstage_diff_hunks(
24624                                false,
24625                                vec![hunk_range.start..hunk_range.start],
24626                                cx,
24627                            );
24628                        });
24629                    }
24630                })
24631        })
24632        .child(
24633            Button::new(("restore", row as u64), "Restore")
24634                .tooltip({
24635                    let focus_handle = editor.focus_handle(cx);
24636                    move |window, cx| {
24637                        Tooltip::for_action_in(
24638                            "Restore Hunk",
24639                            &::git::Restore,
24640                            &focus_handle,
24641                            window,
24642                            cx,
24643                        )
24644                    }
24645                })
24646                .on_click({
24647                    let editor = editor.clone();
24648                    move |_event, window, cx| {
24649                        editor.update(cx, |editor, cx| {
24650                            let snapshot = editor.snapshot(window, cx);
24651                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24652                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24653                        });
24654                    }
24655                })
24656                .disabled(is_created_file),
24657        )
24658        .when(
24659            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24660            |el| {
24661                el.child(
24662                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24663                        .shape(IconButtonShape::Square)
24664                        .icon_size(IconSize::Small)
24665                        // .disabled(!has_multiple_hunks)
24666                        .tooltip({
24667                            let focus_handle = editor.focus_handle(cx);
24668                            move |window, cx| {
24669                                Tooltip::for_action_in(
24670                                    "Next Hunk",
24671                                    &GoToHunk,
24672                                    &focus_handle,
24673                                    window,
24674                                    cx,
24675                                )
24676                            }
24677                        })
24678                        .on_click({
24679                            let editor = editor.clone();
24680                            move |_event, window, cx| {
24681                                editor.update(cx, |editor, cx| {
24682                                    let snapshot = editor.snapshot(window, cx);
24683                                    let position =
24684                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24685                                    editor.go_to_hunk_before_or_after_position(
24686                                        &snapshot,
24687                                        position,
24688                                        Direction::Next,
24689                                        window,
24690                                        cx,
24691                                    );
24692                                    editor.expand_selected_diff_hunks(cx);
24693                                });
24694                            }
24695                        }),
24696                )
24697                .child(
24698                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24699                        .shape(IconButtonShape::Square)
24700                        .icon_size(IconSize::Small)
24701                        // .disabled(!has_multiple_hunks)
24702                        .tooltip({
24703                            let focus_handle = editor.focus_handle(cx);
24704                            move |window, cx| {
24705                                Tooltip::for_action_in(
24706                                    "Previous Hunk",
24707                                    &GoToPreviousHunk,
24708                                    &focus_handle,
24709                                    window,
24710                                    cx,
24711                                )
24712                            }
24713                        })
24714                        .on_click({
24715                            let editor = editor.clone();
24716                            move |_event, window, cx| {
24717                                editor.update(cx, |editor, cx| {
24718                                    let snapshot = editor.snapshot(window, cx);
24719                                    let point =
24720                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24721                                    editor.go_to_hunk_before_or_after_position(
24722                                        &snapshot,
24723                                        point,
24724                                        Direction::Prev,
24725                                        window,
24726                                        cx,
24727                                    );
24728                                    editor.expand_selected_diff_hunks(cx);
24729                                });
24730                            }
24731                        }),
24732                )
24733            },
24734        )
24735        .into_any_element()
24736}
24737
24738pub fn multibuffer_context_lines(cx: &App) -> u32 {
24739    EditorSettings::try_get(cx)
24740        .map(|settings| settings.excerpt_context_lines)
24741        .unwrap_or(2)
24742        .min(32)
24743}