editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  130        language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{
  173    GitGutterSetting, InlayHintSettings, Settings, SettingsLocation, SettingsStore,
  174    update_settings_file,
  175};
  176use smallvec::{SmallVec, smallvec};
  177use snippet::Snippet;
  178use std::{
  179    any::{Any, TypeId},
  180    borrow::Cow,
  181    cell::{OnceCell, RefCell},
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  193use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  194use theme::{
  195    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  196    observe_buffer_font_size_adjustment,
  197};
  198use ui::{
  199    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  200    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  201};
  202use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  203use workspace::{
  204    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  205    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  206    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  207    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  208    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  209    searchable::SearchEvent,
  210};
  211
  212use crate::{
  213    code_context_menus::CompletionsMenuSource,
  214    editor_settings::MultiCursorModifier,
  215    hover_links::{find_url, find_url_from_range},
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233
  234pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  235pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251enum ReportEditorEvent {
  252    Saved { auto_saved: bool },
  253    EditorOpened,
  254    Closed,
  255}
  256
  257impl ReportEditorEvent {
  258    pub fn event_type(&self) -> &'static str {
  259        match self {
  260            Self::Saved { .. } => "Editor Saved",
  261            Self::EditorOpened => "Editor Opened",
  262            Self::Closed => "Editor Closed",
  263        }
  264    }
  265}
  266
  267struct InlineValueCache {
  268    enabled: bool,
  269    inlays: Vec<InlayId>,
  270    refresh_task: Task<Option<()>>,
  271}
  272
  273impl InlineValueCache {
  274    fn new(enabled: bool) -> Self {
  275        Self {
  276            enabled,
  277            inlays: Vec::new(),
  278            refresh_task: Task::ready(None),
  279        }
  280    }
  281}
  282
  283#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  284pub enum InlayId {
  285    EditPrediction(usize),
  286    DebuggerValue(usize),
  287    // LSP
  288    Hint(usize),
  289    Color(usize),
  290}
  291
  292impl InlayId {
  293    fn id(&self) -> usize {
  294        match self {
  295            Self::EditPrediction(id) => *id,
  296            Self::DebuggerValue(id) => *id,
  297            Self::Hint(id) => *id,
  298            Self::Color(id) => *id,
  299        }
  300    }
  301}
  302
  303pub enum ActiveDebugLine {}
  304pub enum DebugStackFrameLine {}
  305enum DocumentHighlightRead {}
  306enum DocumentHighlightWrite {}
  307enum InputComposition {}
  308pub enum PendingInput {}
  309enum SelectedTextHighlight {}
  310
  311pub enum ConflictsOuter {}
  312pub enum ConflictsOurs {}
  313pub enum ConflictsTheirs {}
  314pub enum ConflictsOursMarker {}
  315pub enum ConflictsTheirsMarker {}
  316
  317#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  318pub enum Navigated {
  319    Yes,
  320    No,
  321}
  322
  323impl Navigated {
  324    pub fn from_bool(yes: bool) -> Navigated {
  325        if yes { Navigated::Yes } else { Navigated::No }
  326    }
  327}
  328
  329#[derive(Debug, Clone, PartialEq, Eq)]
  330enum DisplayDiffHunk {
  331    Folded {
  332        display_row: DisplayRow,
  333    },
  334    Unfolded {
  335        is_created_file: bool,
  336        diff_base_byte_range: Range<usize>,
  337        display_row_range: Range<DisplayRow>,
  338        multi_buffer_range: Range<Anchor>,
  339        status: DiffHunkStatus,
  340    },
  341}
  342
  343pub enum HideMouseCursorOrigin {
  344    TypingAction,
  345    MovementAction,
  346}
  347
  348pub fn init_settings(cx: &mut App) {
  349    EditorSettings::register(cx);
  350}
  351
  352pub fn init(cx: &mut App) {
  353    init_settings(cx);
  354
  355    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  356
  357    workspace::register_project_item::<Editor>(cx);
  358    workspace::FollowableViewRegistry::register::<Editor>(cx);
  359    workspace::register_serializable_item::<Editor>(cx);
  360
  361    cx.observe_new(
  362        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  363            workspace.register_action(Editor::new_file);
  364            workspace.register_action(Editor::new_file_vertical);
  365            workspace.register_action(Editor::new_file_horizontal);
  366            workspace.register_action(Editor::cancel_language_server_work);
  367            workspace.register_action(Editor::toggle_focus);
  368        },
  369    )
  370    .detach();
  371
  372    cx.on_action(move |_: &workspace::NewFile, cx| {
  373        let app_state = workspace::AppState::global(cx);
  374        if let Some(app_state) = app_state.upgrade() {
  375            workspace::open_new(
  376                Default::default(),
  377                app_state,
  378                cx,
  379                |workspace, window, cx| {
  380                    Editor::new_file(workspace, &Default::default(), window, cx)
  381                },
  382            )
  383            .detach();
  384        }
  385    });
  386    cx.on_action(move |_: &workspace::NewWindow, cx| {
  387        let app_state = workspace::AppState::global(cx);
  388        if let Some(app_state) = app_state.upgrade() {
  389            workspace::open_new(
  390                Default::default(),
  391                app_state,
  392                cx,
  393                |workspace, window, cx| {
  394                    cx.activate(true);
  395                    Editor::new_file(workspace, &Default::default(), window, cx)
  396                },
  397            )
  398            .detach();
  399        }
  400    });
  401}
  402
  403pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  404    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  405}
  406
  407pub trait DiagnosticRenderer {
  408    fn render_group(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        buffer_id: BufferId,
  412        snapshot: EditorSnapshot,
  413        editor: WeakEntity<Editor>,
  414        cx: &mut App,
  415    ) -> Vec<BlockProperties<Anchor>>;
  416
  417    fn render_hover(
  418        &self,
  419        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  420        range: Range<Point>,
  421        buffer_id: BufferId,
  422        cx: &mut App,
  423    ) -> Option<Entity<markdown::Markdown>>;
  424
  425    fn open_link(
  426        &self,
  427        editor: &mut Editor,
  428        link: SharedString,
  429        window: &mut Window,
  430        cx: &mut Context<Editor>,
  431    );
  432}
  433
  434pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  435
  436impl GlobalDiagnosticRenderer {
  437    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  438        cx.try_global::<Self>().map(|g| g.0.clone())
  439    }
  440}
  441
  442impl gpui::Global for GlobalDiagnosticRenderer {}
  443pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  444    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  445}
  446
  447pub struct SearchWithinRange;
  448
  449trait InvalidationRegion {
  450    fn ranges(&self) -> &[Range<Anchor>];
  451}
  452
  453#[derive(Clone, Debug, PartialEq)]
  454pub enum SelectPhase {
  455    Begin {
  456        position: DisplayPoint,
  457        add: bool,
  458        click_count: usize,
  459    },
  460    BeginColumnar {
  461        position: DisplayPoint,
  462        reset: bool,
  463        mode: ColumnarMode,
  464        goal_column: u32,
  465    },
  466    Extend {
  467        position: DisplayPoint,
  468        click_count: usize,
  469    },
  470    Update {
  471        position: DisplayPoint,
  472        goal_column: u32,
  473        scroll_delta: gpui::Point<f32>,
  474    },
  475    End,
  476}
  477
  478#[derive(Clone, Debug, PartialEq)]
  479pub enum ColumnarMode {
  480    FromMouse,
  481    FromSelection,
  482}
  483
  484#[derive(Clone, Debug)]
  485pub enum SelectMode {
  486    Character,
  487    Word(Range<Anchor>),
  488    Line(Range<Anchor>),
  489    All,
  490}
  491
  492#[derive(Clone, PartialEq, Eq, Debug)]
  493pub enum EditorMode {
  494    SingleLine,
  495    AutoHeight {
  496        min_lines: usize,
  497        max_lines: Option<usize>,
  498    },
  499    Full {
  500        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  501        scale_ui_elements_with_buffer_font_size: bool,
  502        /// When set to `true`, the editor will render a background for the active line.
  503        show_active_line_background: bool,
  504        /// When set to `true`, the editor's height will be determined by its content.
  505        sized_by_content: bool,
  506    },
  507    Minimap {
  508        parent: WeakEntity<Editor>,
  509    },
  510}
  511
  512impl EditorMode {
  513    pub fn full() -> Self {
  514        Self::Full {
  515            scale_ui_elements_with_buffer_font_size: true,
  516            show_active_line_background: true,
  517            sized_by_content: false,
  518        }
  519    }
  520
  521    #[inline]
  522    pub fn is_full(&self) -> bool {
  523        matches!(self, Self::Full { .. })
  524    }
  525
  526    #[inline]
  527    pub fn is_single_line(&self) -> bool {
  528        matches!(self, Self::SingleLine { .. })
  529    }
  530
  531    #[inline]
  532    fn is_minimap(&self) -> bool {
  533        matches!(self, Self::Minimap { .. })
  534    }
  535}
  536
  537#[derive(Copy, Clone, Debug)]
  538pub enum SoftWrap {
  539    /// Prefer not to wrap at all.
  540    ///
  541    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  542    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  543    GitDiff,
  544    /// Prefer a single line generally, unless an overly long line is encountered.
  545    None,
  546    /// Soft wrap lines that exceed the editor width.
  547    EditorWidth,
  548    /// Soft wrap lines at the preferred line length.
  549    Column(u32),
  550    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  551    Bounded(u32),
  552}
  553
  554#[derive(Clone)]
  555pub struct EditorStyle {
  556    pub background: Hsla,
  557    pub border: Hsla,
  558    pub local_player: PlayerColor,
  559    pub text: TextStyle,
  560    pub scrollbar_width: Pixels,
  561    pub syntax: Arc<SyntaxTheme>,
  562    pub status: StatusColors,
  563    pub inlay_hints_style: HighlightStyle,
  564    pub edit_prediction_styles: EditPredictionStyles,
  565    pub unnecessary_code_fade: f32,
  566    pub show_underlines: bool,
  567}
  568
  569impl Default for EditorStyle {
  570    fn default() -> Self {
  571        Self {
  572            background: Hsla::default(),
  573            border: Hsla::default(),
  574            local_player: PlayerColor::default(),
  575            text: TextStyle::default(),
  576            scrollbar_width: Pixels::default(),
  577            syntax: Default::default(),
  578            // HACK: Status colors don't have a real default.
  579            // We should look into removing the status colors from the editor
  580            // style and retrieve them directly from the theme.
  581            status: StatusColors::dark(),
  582            inlay_hints_style: HighlightStyle::default(),
  583            edit_prediction_styles: EditPredictionStyles {
  584                insertion: HighlightStyle::default(),
  585                whitespace: HighlightStyle::default(),
  586            },
  587            unnecessary_code_fade: Default::default(),
  588            show_underlines: true,
  589        }
  590    }
  591}
  592
  593pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  594    let show_background = language_settings::language_settings(None, None, cx)
  595        .inlay_hints
  596        .show_background;
  597
  598    HighlightStyle {
  599        color: Some(cx.theme().status().hint),
  600        background_color: show_background.then(|| cx.theme().status().hint_background),
  601        ..HighlightStyle::default()
  602    }
  603}
  604
  605pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  606    EditPredictionStyles {
  607        insertion: HighlightStyle {
  608            color: Some(cx.theme().status().predictive),
  609            ..HighlightStyle::default()
  610        },
  611        whitespace: HighlightStyle {
  612            background_color: Some(cx.theme().status().created_background),
  613            ..HighlightStyle::default()
  614        },
  615    }
  616}
  617
  618type CompletionId = usize;
  619
  620pub(crate) enum EditDisplayMode {
  621    TabAccept,
  622    DiffPopover,
  623    Inline,
  624}
  625
  626enum EditPrediction {
  627    Edit {
  628        edits: Vec<(Range<Anchor>, String)>,
  629        edit_preview: Option<EditPreview>,
  630        display_mode: EditDisplayMode,
  631        snapshot: BufferSnapshot,
  632    },
  633    Move {
  634        target: Anchor,
  635        snapshot: BufferSnapshot,
  636    },
  637}
  638
  639struct EditPredictionState {
  640    inlay_ids: Vec<InlayId>,
  641    completion: EditPrediction,
  642    completion_id: Option<SharedString>,
  643    invalidation_range: Range<Anchor>,
  644}
  645
  646enum EditPredictionSettings {
  647    Disabled,
  648    Enabled {
  649        show_in_menu: bool,
  650        preview_requires_modifier: bool,
  651    },
  652}
  653
  654enum EditPredictionHighlight {}
  655
  656#[derive(Debug, Clone)]
  657struct InlineDiagnostic {
  658    message: SharedString,
  659    group_id: usize,
  660    is_primary: bool,
  661    start: Point,
  662    severity: lsp::DiagnosticSeverity,
  663}
  664
  665pub enum MenuEditPredictionsPolicy {
  666    Never,
  667    ByProvider,
  668}
  669
  670pub enum EditPredictionPreview {
  671    /// Modifier is not pressed
  672    Inactive { released_too_fast: bool },
  673    /// Modifier pressed
  674    Active {
  675        since: Instant,
  676        previous_scroll_position: Option<ScrollAnchor>,
  677    },
  678}
  679
  680impl EditPredictionPreview {
  681    pub fn released_too_fast(&self) -> bool {
  682        match self {
  683            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  684            EditPredictionPreview::Active { .. } => false,
  685        }
  686    }
  687
  688    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  689        if let EditPredictionPreview::Active {
  690            previous_scroll_position,
  691            ..
  692        } = self
  693        {
  694            *previous_scroll_position = scroll_position;
  695        }
  696    }
  697}
  698
  699pub struct ContextMenuOptions {
  700    pub min_entries_visible: usize,
  701    pub max_entries_visible: usize,
  702    pub placement: Option<ContextMenuPlacement>,
  703}
  704
  705#[derive(Debug, Clone, PartialEq, Eq)]
  706pub enum ContextMenuPlacement {
  707    Above,
  708    Below,
  709}
  710
  711#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  712struct EditorActionId(usize);
  713
  714impl EditorActionId {
  715    pub fn post_inc(&mut self) -> Self {
  716        let answer = self.0;
  717
  718        *self = Self(answer + 1);
  719
  720        Self(answer)
  721    }
  722}
  723
  724// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  725// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  726
  727type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  728type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  729
  730#[derive(Default)]
  731struct ScrollbarMarkerState {
  732    scrollbar_size: Size<Pixels>,
  733    dirty: bool,
  734    markers: Arc<[PaintQuad]>,
  735    pending_refresh: Option<Task<Result<()>>>,
  736}
  737
  738impl ScrollbarMarkerState {
  739    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  740        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  741    }
  742}
  743
  744#[derive(Clone, Copy, PartialEq, Eq)]
  745pub enum MinimapVisibility {
  746    Disabled,
  747    Enabled {
  748        /// The configuration currently present in the users settings.
  749        setting_configuration: bool,
  750        /// Whether to override the currently set visibility from the users setting.
  751        toggle_override: bool,
  752    },
  753}
  754
  755impl MinimapVisibility {
  756    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  757        if mode.is_full() {
  758            Self::Enabled {
  759                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  760                toggle_override: false,
  761            }
  762        } else {
  763            Self::Disabled
  764        }
  765    }
  766
  767    fn hidden(&self) -> Self {
  768        match *self {
  769            Self::Enabled {
  770                setting_configuration,
  771                ..
  772            } => Self::Enabled {
  773                setting_configuration,
  774                toggle_override: setting_configuration,
  775            },
  776            Self::Disabled => Self::Disabled,
  777        }
  778    }
  779
  780    fn disabled(&self) -> bool {
  781        matches!(*self, Self::Disabled)
  782    }
  783
  784    fn settings_visibility(&self) -> bool {
  785        match *self {
  786            Self::Enabled {
  787                setting_configuration,
  788                ..
  789            } => setting_configuration,
  790            _ => false,
  791        }
  792    }
  793
  794    fn visible(&self) -> bool {
  795        match *self {
  796            Self::Enabled {
  797                setting_configuration,
  798                toggle_override,
  799            } => setting_configuration ^ toggle_override,
  800            _ => false,
  801        }
  802    }
  803
  804    fn toggle_visibility(&self) -> Self {
  805        match *self {
  806            Self::Enabled {
  807                toggle_override,
  808                setting_configuration,
  809            } => Self::Enabled {
  810                setting_configuration,
  811                toggle_override: !toggle_override,
  812            },
  813            Self::Disabled => Self::Disabled,
  814        }
  815    }
  816}
  817
  818#[derive(Clone, Debug)]
  819struct RunnableTasks {
  820    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  821    offset: multi_buffer::Anchor,
  822    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  823    column: u32,
  824    // Values of all named captures, including those starting with '_'
  825    extra_variables: HashMap<String, String>,
  826    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  827    context_range: Range<BufferOffset>,
  828}
  829
  830impl RunnableTasks {
  831    fn resolve<'a>(
  832        &'a self,
  833        cx: &'a task::TaskContext,
  834    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  835        self.templates.iter().filter_map(|(kind, template)| {
  836            template
  837                .resolve_task(&kind.to_id_base(), cx)
  838                .map(|task| (kind.clone(), task))
  839        })
  840    }
  841}
  842
  843#[derive(Clone)]
  844pub struct ResolvedTasks {
  845    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  846    position: Anchor,
  847}
  848
  849#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  850struct BufferOffset(usize);
  851
  852/// Addons allow storing per-editor state in other crates (e.g. Vim)
  853pub trait Addon: 'static {
  854    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  855
  856    fn render_buffer_header_controls(
  857        &self,
  858        _: &ExcerptInfo,
  859        _: &Window,
  860        _: &App,
  861    ) -> Option<AnyElement> {
  862        None
  863    }
  864
  865    fn to_any(&self) -> &dyn std::any::Any;
  866
  867    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  868        None
  869    }
  870}
  871
  872struct ChangeLocation {
  873    current: Option<Vec<Anchor>>,
  874    original: Vec<Anchor>,
  875}
  876impl ChangeLocation {
  877    fn locations(&self) -> &[Anchor] {
  878        self.current.as_ref().unwrap_or(&self.original)
  879    }
  880}
  881
  882/// A set of caret positions, registered when the editor was edited.
  883pub struct ChangeList {
  884    changes: Vec<ChangeLocation>,
  885    /// Currently "selected" change.
  886    position: Option<usize>,
  887}
  888
  889impl ChangeList {
  890    pub fn new() -> Self {
  891        Self {
  892            changes: Vec::new(),
  893            position: None,
  894        }
  895    }
  896
  897    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  898    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  899    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  900        if self.changes.is_empty() {
  901            return None;
  902        }
  903
  904        let prev = self.position.unwrap_or(self.changes.len());
  905        let next = if direction == Direction::Prev {
  906            prev.saturating_sub(count)
  907        } else {
  908            (prev + count).min(self.changes.len() - 1)
  909        };
  910        self.position = Some(next);
  911        self.changes.get(next).map(|change| change.locations())
  912    }
  913
  914    /// Adds a new change to the list, resetting the change list position.
  915    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  916        self.position.take();
  917        if let Some(last) = self.changes.last_mut()
  918            && group
  919        {
  920            last.current = Some(new_positions)
  921        } else {
  922            self.changes.push(ChangeLocation {
  923                original: new_positions,
  924                current: None,
  925            });
  926        }
  927    }
  928
  929    pub fn last(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.locations())
  931    }
  932
  933    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  934        self.changes.last().map(|change| change.original.as_slice())
  935    }
  936
  937    pub fn invert_last_group(&mut self) {
  938        if let Some(last) = self.changes.last_mut()
  939            && let Some(current) = last.current.as_mut()
  940        {
  941            mem::swap(&mut last.original, current);
  942        }
  943    }
  944}
  945
  946#[derive(Clone)]
  947struct InlineBlamePopoverState {
  948    scroll_handle: ScrollHandle,
  949    commit_message: Option<ParsedCommitMessage>,
  950    markdown: Entity<Markdown>,
  951}
  952
  953struct InlineBlamePopover {
  954    position: gpui::Point<Pixels>,
  955    hide_task: Option<Task<()>>,
  956    popover_bounds: Option<Bounds<Pixels>>,
  957    popover_state: InlineBlamePopoverState,
  958    keyboard_grace: bool,
  959}
  960
  961enum SelectionDragState {
  962    /// State when no drag related activity is detected.
  963    None,
  964    /// State when the mouse is down on a selection that is about to be dragged.
  965    ReadyToDrag {
  966        selection: Selection<Anchor>,
  967        click_position: gpui::Point<Pixels>,
  968        mouse_down_time: Instant,
  969    },
  970    /// State when the mouse is dragging the selection in the editor.
  971    Dragging {
  972        selection: Selection<Anchor>,
  973        drop_cursor: Selection<Anchor>,
  974        hide_drop_cursor: bool,
  975    },
  976}
  977
  978enum ColumnarSelectionState {
  979    FromMouse {
  980        selection_tail: Anchor,
  981        display_point: Option<DisplayPoint>,
  982    },
  983    FromSelection {
  984        selection_tail: Anchor,
  985    },
  986}
  987
  988/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  989/// a breakpoint on them.
  990#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  991struct PhantomBreakpointIndicator {
  992    display_row: DisplayRow,
  993    /// There's a small debounce between hovering over the line and showing the indicator.
  994    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  995    is_active: bool,
  996    collides_with_existing_breakpoint: bool,
  997}
  998
  999/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1000///
 1001/// See the [module level documentation](self) for more information.
 1002pub struct Editor {
 1003    focus_handle: FocusHandle,
 1004    last_focused_descendant: Option<WeakFocusHandle>,
 1005    /// The text buffer being edited
 1006    buffer: Entity<MultiBuffer>,
 1007    /// Map of how text in the buffer should be displayed.
 1008    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1009    pub display_map: Entity<DisplayMap>,
 1010    placeholder_display_map: Option<Entity<DisplayMap>>,
 1011    pub selections: SelectionsCollection,
 1012    pub scroll_manager: ScrollManager,
 1013    /// When inline assist editors are linked, they all render cursors because
 1014    /// typing enters text into each of them, even the ones that aren't focused.
 1015    pub(crate) show_cursor_when_unfocused: bool,
 1016    columnar_selection_state: Option<ColumnarSelectionState>,
 1017    add_selections_state: Option<AddSelectionsState>,
 1018    select_next_state: Option<SelectNextState>,
 1019    select_prev_state: Option<SelectNextState>,
 1020    selection_history: SelectionHistory,
 1021    defer_selection_effects: bool,
 1022    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1023    autoclose_regions: Vec<AutocloseRegion>,
 1024    snippet_stack: InvalidationStack<SnippetState>,
 1025    select_syntax_node_history: SelectSyntaxNodeHistory,
 1026    ime_transaction: Option<TransactionId>,
 1027    pub diagnostics_max_severity: DiagnosticSeverity,
 1028    active_diagnostics: ActiveDiagnostic,
 1029    show_inline_diagnostics: bool,
 1030    inline_diagnostics_update: Task<()>,
 1031    inline_diagnostics_enabled: bool,
 1032    diagnostics_enabled: bool,
 1033    word_completions_enabled: bool,
 1034    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1035    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1036    hard_wrap: Option<usize>,
 1037    project: Option<Entity<Project>>,
 1038    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1039    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1040    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1041    blink_manager: Entity<BlinkManager>,
 1042    show_cursor_names: bool,
 1043    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1044    pub show_local_selections: bool,
 1045    mode: EditorMode,
 1046    show_breadcrumbs: bool,
 1047    show_gutter: bool,
 1048    show_scrollbars: ScrollbarAxes,
 1049    minimap_visibility: MinimapVisibility,
 1050    offset_content: bool,
 1051    disable_expand_excerpt_buttons: bool,
 1052    show_line_numbers: Option<bool>,
 1053    use_relative_line_numbers: Option<bool>,
 1054    show_git_diff_gutter: Option<bool>,
 1055    show_code_actions: Option<bool>,
 1056    show_runnables: Option<bool>,
 1057    show_breakpoints: Option<bool>,
 1058    show_wrap_guides: Option<bool>,
 1059    show_indent_guides: Option<bool>,
 1060    highlight_order: usize,
 1061    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1062    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1063    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1064    scrollbar_marker_state: ScrollbarMarkerState,
 1065    active_indent_guides_state: ActiveIndentGuidesState,
 1066    nav_history: Option<ItemNavHistory>,
 1067    context_menu: RefCell<Option<CodeContextMenu>>,
 1068    context_menu_options: Option<ContextMenuOptions>,
 1069    mouse_context_menu: Option<MouseContextMenu>,
 1070    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1071    inline_blame_popover: Option<InlineBlamePopover>,
 1072    inline_blame_popover_show_task: Option<Task<()>>,
 1073    signature_help_state: SignatureHelpState,
 1074    auto_signature_help: Option<bool>,
 1075    find_all_references_task_sources: Vec<Anchor>,
 1076    next_completion_id: CompletionId,
 1077    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1078    code_actions_task: Option<Task<Result<()>>>,
 1079    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1080    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    document_highlights_task: Option<Task<()>>,
 1082    linked_editing_range_task: Option<Task<Option<()>>>,
 1083    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1084    pending_rename: Option<RenameState>,
 1085    searchable: bool,
 1086    cursor_shape: CursorShape,
 1087    current_line_highlight: Option<CurrentLineHighlight>,
 1088    collapse_matches: bool,
 1089    autoindent_mode: Option<AutoindentMode>,
 1090    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1091    input_enabled: bool,
 1092    use_modal_editing: bool,
 1093    read_only: bool,
 1094    leader_id: Option<CollaboratorId>,
 1095    remote_id: Option<ViewId>,
 1096    pub hover_state: HoverState,
 1097    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1098    gutter_hovered: bool,
 1099    hovered_link_state: Option<HoveredLinkState>,
 1100    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1101    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1102    active_edit_prediction: Option<EditPredictionState>,
 1103    /// Used to prevent flickering as the user types while the menu is open
 1104    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1105    edit_prediction_settings: EditPredictionSettings,
 1106    edit_predictions_hidden_for_vim_mode: bool,
 1107    show_edit_predictions_override: Option<bool>,
 1108    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1109    edit_prediction_preview: EditPredictionPreview,
 1110    edit_prediction_indent_conflict: bool,
 1111    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1112    inlay_hint_cache: InlayHintCache,
 1113    next_inlay_id: usize,
 1114    _subscriptions: Vec<Subscription>,
 1115    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1116    gutter_dimensions: GutterDimensions,
 1117    style: Option<EditorStyle>,
 1118    text_style_refinement: Option<TextStyleRefinement>,
 1119    next_editor_action_id: EditorActionId,
 1120    editor_actions: Rc<
 1121        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1122    >,
 1123    use_autoclose: bool,
 1124    use_auto_surround: bool,
 1125    auto_replace_emoji_shortcode: bool,
 1126    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1127    show_git_blame_gutter: bool,
 1128    show_git_blame_inline: bool,
 1129    show_git_blame_inline_delay_task: Option<Task<()>>,
 1130    git_blame_inline_enabled: bool,
 1131    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1132    serialize_dirty_buffers: bool,
 1133    show_selection_menu: Option<bool>,
 1134    blame: Option<Entity<GitBlame>>,
 1135    blame_subscription: Option<Subscription>,
 1136    custom_context_menu: Option<
 1137        Box<
 1138            dyn 'static
 1139                + Fn(
 1140                    &mut Self,
 1141                    DisplayPoint,
 1142                    &mut Window,
 1143                    &mut Context<Self>,
 1144                ) -> Option<Entity<ui::ContextMenu>>,
 1145        >,
 1146    >,
 1147    last_bounds: Option<Bounds<Pixels>>,
 1148    last_position_map: Option<Rc<PositionMap>>,
 1149    expect_bounds_change: Option<Bounds<Pixels>>,
 1150    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1151    tasks_update_task: Option<Task<()>>,
 1152    breakpoint_store: Option<Entity<BreakpointStore>>,
 1153    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1154    hovered_diff_hunk_row: Option<DisplayRow>,
 1155    pull_diagnostics_task: Task<()>,
 1156    in_project_search: bool,
 1157    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1158    breadcrumb_header: Option<String>,
 1159    focused_block: Option<FocusedBlock>,
 1160    next_scroll_position: NextScrollCursorCenterTopBottom,
 1161    addons: HashMap<TypeId, Box<dyn Addon>>,
 1162    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1163    load_diff_task: Option<Shared<Task<()>>>,
 1164    /// Whether we are temporarily displaying a diff other than git's
 1165    temporary_diff_override: bool,
 1166    selection_mark_mode: bool,
 1167    toggle_fold_multiple_buffers: Task<()>,
 1168    _scroll_cursor_center_top_bottom_task: Task<()>,
 1169    serialize_selections: Task<()>,
 1170    serialize_folds: Task<()>,
 1171    mouse_cursor_hidden: bool,
 1172    minimap: Option<Entity<Self>>,
 1173    hide_mouse_mode: HideMouseMode,
 1174    pub change_list: ChangeList,
 1175    inline_value_cache: InlineValueCache,
 1176    selection_drag_state: SelectionDragState,
 1177    next_color_inlay_id: usize,
 1178    colors: Option<LspColorData>,
 1179    folding_newlines: Task<()>,
 1180    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1181}
 1182
 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1184enum NextScrollCursorCenterTopBottom {
 1185    #[default]
 1186    Center,
 1187    Top,
 1188    Bottom,
 1189}
 1190
 1191impl NextScrollCursorCenterTopBottom {
 1192    fn next(&self) -> Self {
 1193        match self {
 1194            Self::Center => Self::Top,
 1195            Self::Top => Self::Bottom,
 1196            Self::Bottom => Self::Center,
 1197        }
 1198    }
 1199}
 1200
 1201#[derive(Clone)]
 1202pub struct EditorSnapshot {
 1203    pub mode: EditorMode,
 1204    show_gutter: bool,
 1205    show_line_numbers: Option<bool>,
 1206    show_git_diff_gutter: Option<bool>,
 1207    show_code_actions: Option<bool>,
 1208    show_runnables: Option<bool>,
 1209    show_breakpoints: Option<bool>,
 1210    git_blame_gutter_max_author_length: Option<usize>,
 1211    pub display_snapshot: DisplaySnapshot,
 1212    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1213    is_focused: bool,
 1214    scroll_anchor: ScrollAnchor,
 1215    ongoing_scroll: OngoingScroll,
 1216    current_line_highlight: CurrentLineHighlight,
 1217    gutter_hovered: bool,
 1218}
 1219
 1220#[derive(Default, Debug, Clone, Copy)]
 1221pub struct GutterDimensions {
 1222    pub left_padding: Pixels,
 1223    pub right_padding: Pixels,
 1224    pub width: Pixels,
 1225    pub margin: Pixels,
 1226    pub git_blame_entries_width: Option<Pixels>,
 1227}
 1228
 1229impl GutterDimensions {
 1230    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1231        Self {
 1232            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1233            ..Default::default()
 1234        }
 1235    }
 1236
 1237    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1238        -cx.text_system().descent(font_id, font_size)
 1239    }
 1240    /// The full width of the space taken up by the gutter.
 1241    pub fn full_width(&self) -> Pixels {
 1242        self.margin + self.width
 1243    }
 1244
 1245    /// The width of the space reserved for the fold indicators,
 1246    /// use alongside 'justify_end' and `gutter_width` to
 1247    /// right align content with the line numbers
 1248    pub fn fold_area_width(&self) -> Pixels {
 1249        self.margin + self.right_padding
 1250    }
 1251}
 1252
 1253struct CharacterDimensions {
 1254    em_width: Pixels,
 1255    em_advance: Pixels,
 1256    line_height: Pixels,
 1257}
 1258
 1259#[derive(Debug)]
 1260pub struct RemoteSelection {
 1261    pub replica_id: ReplicaId,
 1262    pub selection: Selection<Anchor>,
 1263    pub cursor_shape: CursorShape,
 1264    pub collaborator_id: CollaboratorId,
 1265    pub line_mode: bool,
 1266    pub user_name: Option<SharedString>,
 1267    pub color: PlayerColor,
 1268}
 1269
 1270#[derive(Clone, Debug)]
 1271struct SelectionHistoryEntry {
 1272    selections: Arc<[Selection<Anchor>]>,
 1273    select_next_state: Option<SelectNextState>,
 1274    select_prev_state: Option<SelectNextState>,
 1275    add_selections_state: Option<AddSelectionsState>,
 1276}
 1277
 1278#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1279enum SelectionHistoryMode {
 1280    Normal,
 1281    Undoing,
 1282    Redoing,
 1283    Skipping,
 1284}
 1285
 1286#[derive(Clone, PartialEq, Eq, Hash)]
 1287struct HoveredCursor {
 1288    replica_id: u16,
 1289    selection_id: usize,
 1290}
 1291
 1292impl Default for SelectionHistoryMode {
 1293    fn default() -> Self {
 1294        Self::Normal
 1295    }
 1296}
 1297
 1298#[derive(Debug)]
 1299/// SelectionEffects controls the side-effects of updating the selection.
 1300///
 1301/// The default behaviour does "what you mostly want":
 1302/// - it pushes to the nav history if the cursor moved by >10 lines
 1303/// - it re-triggers completion requests
 1304/// - it scrolls to fit
 1305///
 1306/// You might want to modify these behaviours. For example when doing a "jump"
 1307/// like go to definition, we always want to add to nav history; but when scrolling
 1308/// in vim mode we never do.
 1309///
 1310/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1311/// move.
 1312#[derive(Clone)]
 1313pub struct SelectionEffects {
 1314    nav_history: Option<bool>,
 1315    completions: bool,
 1316    scroll: Option<Autoscroll>,
 1317}
 1318
 1319impl Default for SelectionEffects {
 1320    fn default() -> Self {
 1321        Self {
 1322            nav_history: None,
 1323            completions: true,
 1324            scroll: Some(Autoscroll::fit()),
 1325        }
 1326    }
 1327}
 1328impl SelectionEffects {
 1329    pub fn scroll(scroll: Autoscroll) -> Self {
 1330        Self {
 1331            scroll: Some(scroll),
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn no_scroll() -> Self {
 1337        Self {
 1338            scroll: None,
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn completions(self, completions: bool) -> Self {
 1344        Self {
 1345            completions,
 1346            ..self
 1347        }
 1348    }
 1349
 1350    pub fn nav_history(self, nav_history: bool) -> Self {
 1351        Self {
 1352            nav_history: Some(nav_history),
 1353            ..self
 1354        }
 1355    }
 1356}
 1357
 1358struct DeferredSelectionEffectsState {
 1359    changed: bool,
 1360    effects: SelectionEffects,
 1361    old_cursor_position: Anchor,
 1362    history_entry: SelectionHistoryEntry,
 1363}
 1364
 1365#[derive(Default)]
 1366struct SelectionHistory {
 1367    #[allow(clippy::type_complexity)]
 1368    selections_by_transaction:
 1369        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1370    mode: SelectionHistoryMode,
 1371    undo_stack: VecDeque<SelectionHistoryEntry>,
 1372    redo_stack: VecDeque<SelectionHistoryEntry>,
 1373}
 1374
 1375impl SelectionHistory {
 1376    #[track_caller]
 1377    fn insert_transaction(
 1378        &mut self,
 1379        transaction_id: TransactionId,
 1380        selections: Arc<[Selection<Anchor>]>,
 1381    ) {
 1382        if selections.is_empty() {
 1383            log::error!(
 1384                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1385                std::panic::Location::caller()
 1386            );
 1387            return;
 1388        }
 1389        self.selections_by_transaction
 1390            .insert(transaction_id, (selections, None));
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction(
 1395        &self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get(&transaction_id)
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction_mut(
 1403        &mut self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get_mut(&transaction_id)
 1407    }
 1408
 1409    fn push(&mut self, entry: SelectionHistoryEntry) {
 1410        if !entry.selections.is_empty() {
 1411            match self.mode {
 1412                SelectionHistoryMode::Normal => {
 1413                    self.push_undo(entry);
 1414                    self.redo_stack.clear();
 1415                }
 1416                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1417                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1418                SelectionHistoryMode::Skipping => {}
 1419            }
 1420        }
 1421    }
 1422
 1423    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1424        if self
 1425            .undo_stack
 1426            .back()
 1427            .is_none_or(|e| e.selections != entry.selections)
 1428        {
 1429            self.undo_stack.push_back(entry);
 1430            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1431                self.undo_stack.pop_front();
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .redo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.redo_stack.push_back(entry);
 1443            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.redo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448}
 1449
 1450#[derive(Clone, Copy)]
 1451pub struct RowHighlightOptions {
 1452    pub autoscroll: bool,
 1453    pub include_gutter: bool,
 1454}
 1455
 1456impl Default for RowHighlightOptions {
 1457    fn default() -> Self {
 1458        Self {
 1459            autoscroll: Default::default(),
 1460            include_gutter: true,
 1461        }
 1462    }
 1463}
 1464
 1465struct RowHighlight {
 1466    index: usize,
 1467    range: Range<Anchor>,
 1468    color: Hsla,
 1469    options: RowHighlightOptions,
 1470    type_id: TypeId,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsState {
 1475    groups: Vec<AddSelectionsGroup>,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsGroup {
 1480    above: bool,
 1481    stack: Vec<usize>,
 1482}
 1483
 1484#[derive(Clone)]
 1485struct SelectNextState {
 1486    query: AhoCorasick,
 1487    wordwise: bool,
 1488    done: bool,
 1489}
 1490
 1491impl std::fmt::Debug for SelectNextState {
 1492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1493        f.debug_struct(std::any::type_name::<Self>())
 1494            .field("wordwise", &self.wordwise)
 1495            .field("done", &self.done)
 1496            .finish()
 1497    }
 1498}
 1499
 1500#[derive(Debug)]
 1501struct AutocloseRegion {
 1502    selection_id: usize,
 1503    range: Range<Anchor>,
 1504    pair: BracketPair,
 1505}
 1506
 1507#[derive(Debug)]
 1508struct SnippetState {
 1509    ranges: Vec<Vec<Range<Anchor>>>,
 1510    active_index: usize,
 1511    choices: Vec<Option<Vec<String>>>,
 1512}
 1513
 1514#[doc(hidden)]
 1515pub struct RenameState {
 1516    pub range: Range<Anchor>,
 1517    pub old_name: Arc<str>,
 1518    pub editor: Entity<Editor>,
 1519    block_id: CustomBlockId,
 1520}
 1521
 1522struct InvalidationStack<T>(Vec<T>);
 1523
 1524struct RegisteredEditPredictionProvider {
 1525    provider: Arc<dyn EditPredictionProviderHandle>,
 1526    _subscription: Subscription,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530pub struct ActiveDiagnosticGroup {
 1531    pub active_range: Range<Anchor>,
 1532    pub active_message: String,
 1533    pub group_id: usize,
 1534    pub blocks: HashSet<CustomBlockId>,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538
 1539pub(crate) enum ActiveDiagnostic {
 1540    None,
 1541    All,
 1542    Group(ActiveDiagnosticGroup),
 1543}
 1544
 1545#[derive(Serialize, Deserialize, Clone, Debug)]
 1546pub struct ClipboardSelection {
 1547    /// The number of bytes in this selection.
 1548    pub len: usize,
 1549    /// Whether this was a full-line selection.
 1550    pub is_entire_line: bool,
 1551    /// The indentation of the first line when this content was originally copied.
 1552    pub first_line_indent: u32,
 1553}
 1554
 1555// selections, scroll behavior, was newest selection reversed
 1556type SelectSyntaxNodeHistoryState = (
 1557    Box<[Selection<usize>]>,
 1558    SelectSyntaxNodeScrollBehavior,
 1559    bool,
 1560);
 1561
 1562#[derive(Default)]
 1563struct SelectSyntaxNodeHistory {
 1564    stack: Vec<SelectSyntaxNodeHistoryState>,
 1565    // disable temporarily to allow changing selections without losing the stack
 1566    pub disable_clearing: bool,
 1567}
 1568
 1569impl SelectSyntaxNodeHistory {
 1570    pub fn try_clear(&mut self) {
 1571        if !self.disable_clearing {
 1572            self.stack.clear();
 1573        }
 1574    }
 1575
 1576    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1577        self.stack.push(selection);
 1578    }
 1579
 1580    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1581        self.stack.pop()
 1582    }
 1583}
 1584
 1585enum SelectSyntaxNodeScrollBehavior {
 1586    CursorTop,
 1587    FitSelection,
 1588    CursorBottom,
 1589}
 1590
 1591#[derive(Debug)]
 1592pub(crate) struct NavigationData {
 1593    cursor_anchor: Anchor,
 1594    cursor_position: Point,
 1595    scroll_anchor: ScrollAnchor,
 1596    scroll_top_row: u32,
 1597}
 1598
 1599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1600pub enum GotoDefinitionKind {
 1601    Symbol,
 1602    Declaration,
 1603    Type,
 1604    Implementation,
 1605}
 1606
 1607#[derive(Debug, Clone)]
 1608enum InlayHintRefreshReason {
 1609    ModifiersChanged(bool),
 1610    Toggle(bool),
 1611    SettingsChange(InlayHintSettings),
 1612    NewLinesShown,
 1613    BufferEdited(HashSet<Arc<Language>>),
 1614    RefreshRequested,
 1615    ExcerptsRemoved(Vec<ExcerptId>),
 1616}
 1617
 1618impl InlayHintRefreshReason {
 1619    fn description(&self) -> &'static str {
 1620        match self {
 1621            Self::ModifiersChanged(_) => "modifiers changed",
 1622            Self::Toggle(_) => "toggle",
 1623            Self::SettingsChange(_) => "settings change",
 1624            Self::NewLinesShown => "new lines shown",
 1625            Self::BufferEdited(_) => "buffer edited",
 1626            Self::RefreshRequested => "refresh requested",
 1627            Self::ExcerptsRemoved(_) => "excerpts removed",
 1628        }
 1629    }
 1630}
 1631
 1632pub enum FormatTarget {
 1633    Buffers(HashSet<Entity<Buffer>>),
 1634    Ranges(Vec<Range<MultiBufferPoint>>),
 1635}
 1636
 1637pub(crate) struct FocusedBlock {
 1638    id: BlockId,
 1639    focus_handle: WeakFocusHandle,
 1640}
 1641
 1642#[derive(Clone)]
 1643enum JumpData {
 1644    MultiBufferRow {
 1645        row: MultiBufferRow,
 1646        line_offset_from_top: u32,
 1647    },
 1648    MultiBufferPoint {
 1649        excerpt_id: ExcerptId,
 1650        position: Point,
 1651        anchor: text::Anchor,
 1652        line_offset_from_top: u32,
 1653    },
 1654}
 1655
 1656pub enum MultibufferSelectionMode {
 1657    First,
 1658    All,
 1659}
 1660
 1661#[derive(Clone, Copy, Debug, Default)]
 1662pub struct RewrapOptions {
 1663    pub override_language_settings: bool,
 1664    pub preserve_existing_whitespace: bool,
 1665}
 1666
 1667impl Editor {
 1668    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_height(
 1681        min_lines: usize,
 1682        max_lines: usize,
 1683        window: &mut Window,
 1684        cx: &mut Context<Self>,
 1685    ) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(
 1689            EditorMode::AutoHeight {
 1690                min_lines,
 1691                max_lines: Some(max_lines),
 1692            },
 1693            buffer,
 1694            None,
 1695            window,
 1696            cx,
 1697        )
 1698    }
 1699
 1700    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1701    /// The editor grows as tall as needed to fit its content.
 1702    pub fn auto_height_unbounded(
 1703        min_lines: usize,
 1704        window: &mut Window,
 1705        cx: &mut Context<Self>,
 1706    ) -> Self {
 1707        let buffer = cx.new(|cx| Buffer::local("", cx));
 1708        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1709        Self::new(
 1710            EditorMode::AutoHeight {
 1711                min_lines,
 1712                max_lines: None,
 1713            },
 1714            buffer,
 1715            None,
 1716            window,
 1717            cx,
 1718        )
 1719    }
 1720
 1721    pub fn for_buffer(
 1722        buffer: Entity<Buffer>,
 1723        project: Option<Entity<Project>>,
 1724        window: &mut Window,
 1725        cx: &mut Context<Self>,
 1726    ) -> Self {
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::full(), buffer, project, window, cx)
 1729    }
 1730
 1731    pub fn for_multibuffer(
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Self::new(EditorMode::full(), buffer, project, window, cx)
 1738    }
 1739
 1740    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let mut clone = Self::new(
 1742            self.mode.clone(),
 1743            self.buffer.clone(),
 1744            self.project.clone(),
 1745            window,
 1746            cx,
 1747        );
 1748        self.display_map.update(cx, |display_map, cx| {
 1749            let snapshot = display_map.snapshot(cx);
 1750            clone.display_map.update(cx, |display_map, cx| {
 1751                display_map.set_state(&snapshot, cx);
 1752            });
 1753        });
 1754        clone.folds_did_change(cx);
 1755        clone.selections.clone_state(&self.selections);
 1756        clone.scroll_manager.clone_state(&self.scroll_manager);
 1757        clone.searchable = self.searchable;
 1758        clone.read_only = self.read_only;
 1759        clone
 1760    }
 1761
 1762    pub fn new(
 1763        mode: EditorMode,
 1764        buffer: Entity<MultiBuffer>,
 1765        project: Option<Entity<Project>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        Editor::new_internal(mode, buffer, project, None, window, cx)
 1770    }
 1771
 1772    fn new_internal(
 1773        mode: EditorMode,
 1774        buffer: Entity<MultiBuffer>,
 1775        project: Option<Entity<Project>>,
 1776        display_map: Option<Entity<DisplayMap>>,
 1777        window: &mut Window,
 1778        cx: &mut Context<Self>,
 1779    ) -> Self {
 1780        debug_assert!(
 1781            display_map.is_none() || mode.is_minimap(),
 1782            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1783        );
 1784
 1785        let full_mode = mode.is_full();
 1786        let is_minimap = mode.is_minimap();
 1787        let diagnostics_max_severity = if full_mode {
 1788            EditorSettings::get_global(cx)
 1789                .diagnostics_max_severity
 1790                .unwrap_or(DiagnosticSeverity::Hint)
 1791        } else {
 1792            DiagnosticSeverity::Off
 1793        };
 1794        let style = window.text_style();
 1795        let font_size = style.font_size.to_pixels(window.rem_size());
 1796        let editor = cx.entity().downgrade();
 1797        let fold_placeholder = FoldPlaceholder {
 1798            constrain_width: false,
 1799            render: Arc::new(move |fold_id, fold_range, cx| {
 1800                let editor = editor.clone();
 1801                div()
 1802                    .id(fold_id)
 1803                    .bg(cx.theme().colors().ghost_element_background)
 1804                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1805                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1806                    .rounded_xs()
 1807                    .size_full()
 1808                    .cursor_pointer()
 1809                    .child("")
 1810                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1811                    .on_click(move |_, _window, cx| {
 1812                        editor
 1813                            .update(cx, |editor, cx| {
 1814                                editor.unfold_ranges(
 1815                                    &[fold_range.start..fold_range.end],
 1816                                    true,
 1817                                    false,
 1818                                    cx,
 1819                                );
 1820                                cx.stop_propagation();
 1821                            })
 1822                            .ok();
 1823                    })
 1824                    .into_any()
 1825            }),
 1826            merge_adjacent: true,
 1827            ..FoldPlaceholder::default()
 1828        };
 1829        let display_map = display_map.unwrap_or_else(|| {
 1830            cx.new(|cx| {
 1831                DisplayMap::new(
 1832                    buffer.clone(),
 1833                    style.font(),
 1834                    font_size,
 1835                    None,
 1836                    FILE_HEADER_HEIGHT,
 1837                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1838                    fold_placeholder,
 1839                    diagnostics_max_severity,
 1840                    cx,
 1841                )
 1842            })
 1843        });
 1844
 1845        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1846
 1847        let blink_manager = cx.new(|cx| {
 1848            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1849            if is_minimap {
 1850                blink_manager.disable(cx);
 1851            }
 1852            blink_manager
 1853        });
 1854
 1855        let soft_wrap_mode_override =
 1856            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1857
 1858        let mut project_subscriptions = Vec::new();
 1859        if full_mode && let Some(project) = project.as_ref() {
 1860            project_subscriptions.push(cx.subscribe_in(
 1861                project,
 1862                window,
 1863                |editor, _, event, window, cx| match event {
 1864                    project::Event::RefreshCodeLens => {
 1865                        // we always query lens with actions, without storing them, always refreshing them
 1866                    }
 1867                    project::Event::RefreshInlayHints => {
 1868                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1869                    }
 1870                    project::Event::LanguageServerAdded(..)
 1871                    | project::Event::LanguageServerRemoved(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1898                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1899                        }
 1900                    }
 1901
 1902                    project::Event::EntryRenamed(transaction) => {
 1903                        let Some(workspace) = editor.workspace() else {
 1904                            return;
 1905                        };
 1906                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1907                        else {
 1908                            return;
 1909                        };
 1910                        if active_editor.entity_id() == cx.entity_id() {
 1911                            let edited_buffers_already_open = {
 1912                                let other_editors: Vec<Entity<Editor>> = workspace
 1913                                    .read(cx)
 1914                                    .panes()
 1915                                    .iter()
 1916                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1917                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1918                                    .collect();
 1919
 1920                                transaction.0.keys().all(|buffer| {
 1921                                    other_editors.iter().any(|editor| {
 1922                                        let multi_buffer = editor.read(cx).buffer();
 1923                                        multi_buffer.read(cx).is_singleton()
 1924                                            && multi_buffer.read(cx).as_singleton().map_or(
 1925                                                false,
 1926                                                |singleton| {
 1927                                                    singleton.entity_id() == buffer.entity_id()
 1928                                                },
 1929                                            )
 1930                                    })
 1931                                })
 1932                            };
 1933
 1934                            if !edited_buffers_already_open {
 1935                                let workspace = workspace.downgrade();
 1936                                let transaction = transaction.clone();
 1937                                cx.defer_in(window, move |_, window, cx| {
 1938                                    cx.spawn_in(window, async move |editor, cx| {
 1939                                        Self::open_project_transaction(
 1940                                            &editor,
 1941                                            workspace,
 1942                                            transaction,
 1943                                            "Rename".to_string(),
 1944                                            cx,
 1945                                        )
 1946                                        .await
 1947                                        .ok()
 1948                                    })
 1949                                    .detach();
 1950                                });
 1951                            }
 1952                        }
 1953                    }
 1954
 1955                    _ => {}
 1956                },
 1957            ));
 1958            if let Some(task_inventory) = project
 1959                .read(cx)
 1960                .task_store()
 1961                .read(cx)
 1962                .task_inventory()
 1963                .cloned()
 1964            {
 1965                project_subscriptions.push(cx.observe_in(
 1966                    &task_inventory,
 1967                    window,
 1968                    |editor, _, window, cx| {
 1969                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1970                    },
 1971                ));
 1972            };
 1973
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                &project.read(cx).breakpoint_store(),
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    BreakpointStoreEvent::ClearDebugLines => {
 1979                        editor.clear_row_highlights::<ActiveDebugLine>();
 1980                        editor.refresh_inline_values(cx);
 1981                    }
 1982                    BreakpointStoreEvent::SetDebugLine => {
 1983                        if editor.go_to_active_debug_line(window, cx) {
 1984                            cx.stop_propagation();
 1985                        }
 1986
 1987                        editor.refresh_inline_values(cx);
 1988                    }
 1989                    _ => {}
 1990                },
 1991            ));
 1992            let git_store = project.read(cx).git_store().clone();
 1993            let project = project.clone();
 1994            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1995                if let GitStoreEvent::RepositoryUpdated(
 1996                    _,
 1997                    RepositoryEvent::Updated {
 1998                        new_instance: true, ..
 1999                    },
 2000                    _,
 2001                ) = event
 2002                {
 2003                    this.load_diff_task = Some(
 2004                        update_uncommitted_diff_for_buffer(
 2005                            cx.entity(),
 2006                            &project,
 2007                            this.buffer.read(cx).all_buffers(),
 2008                            this.buffer.clone(),
 2009                            cx,
 2010                        )
 2011                        .shared(),
 2012                    );
 2013                }
 2014            }));
 2015        }
 2016
 2017        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2018
 2019        let inlay_hint_settings =
 2020            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2021        let focus_handle = cx.focus_handle();
 2022        if !is_minimap {
 2023            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2024                .detach();
 2025            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2026                .detach();
 2027            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2028                .detach();
 2029            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2030                .detach();
 2031            cx.observe_pending_input(window, Self::observe_pending_input)
 2032                .detach();
 2033        }
 2034
 2035        let show_indent_guides =
 2036            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2037                Some(false)
 2038            } else {
 2039                None
 2040            };
 2041
 2042        let breakpoint_store = match (&mode, project.as_ref()) {
 2043            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2044            _ => None,
 2045        };
 2046
 2047        let mut code_action_providers = Vec::new();
 2048        let mut load_uncommitted_diff = None;
 2049        if let Some(project) = project.clone() {
 2050            load_uncommitted_diff = Some(
 2051                update_uncommitted_diff_for_buffer(
 2052                    cx.entity(),
 2053                    &project,
 2054                    buffer.read(cx).all_buffers(),
 2055                    buffer.clone(),
 2056                    cx,
 2057                )
 2058                .shared(),
 2059            );
 2060            code_action_providers.push(Rc::new(project) as Rc<_>);
 2061        }
 2062
 2063        let mut editor = Self {
 2064            focus_handle,
 2065            show_cursor_when_unfocused: false,
 2066            last_focused_descendant: None,
 2067            buffer: buffer.clone(),
 2068            display_map: display_map.clone(),
 2069            placeholder_display_map: None,
 2070            selections,
 2071            scroll_manager: ScrollManager::new(cx),
 2072            columnar_selection_state: None,
 2073            add_selections_state: None,
 2074            select_next_state: None,
 2075            select_prev_state: None,
 2076            selection_history: SelectionHistory::default(),
 2077            defer_selection_effects: false,
 2078            deferred_selection_effects_state: None,
 2079            autoclose_regions: Vec::new(),
 2080            snippet_stack: InvalidationStack::default(),
 2081            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2082            ime_transaction: None,
 2083            active_diagnostics: ActiveDiagnostic::None,
 2084            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2085            inline_diagnostics_update: Task::ready(()),
 2086            inline_diagnostics: Vec::new(),
 2087            soft_wrap_mode_override,
 2088            diagnostics_max_severity,
 2089            hard_wrap: None,
 2090            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2092            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2093            project,
 2094            blink_manager: blink_manager.clone(),
 2095            show_local_selections: true,
 2096            show_scrollbars: ScrollbarAxes {
 2097                horizontal: full_mode,
 2098                vertical: full_mode,
 2099            },
 2100            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2101            offset_content: !matches!(mode, EditorMode::SingleLine),
 2102            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2103            show_gutter: full_mode,
 2104            show_line_numbers: (!full_mode).then_some(false),
 2105            use_relative_line_numbers: None,
 2106            disable_expand_excerpt_buttons: !full_mode,
 2107            show_git_diff_gutter: None,
 2108            show_code_actions: None,
 2109            show_runnables: None,
 2110            show_breakpoints: None,
 2111            show_wrap_guides: None,
 2112            show_indent_guides,
 2113            highlight_order: 0,
 2114            highlighted_rows: HashMap::default(),
 2115            background_highlights: HashMap::default(),
 2116            gutter_highlights: HashMap::default(),
 2117            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2118            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2119            nav_history: None,
 2120            context_menu: RefCell::new(None),
 2121            context_menu_options: None,
 2122            mouse_context_menu: None,
 2123            completion_tasks: Vec::new(),
 2124            inline_blame_popover: None,
 2125            inline_blame_popover_show_task: None,
 2126            signature_help_state: SignatureHelpState::default(),
 2127            auto_signature_help: None,
 2128            find_all_references_task_sources: Vec::new(),
 2129            next_completion_id: 0,
 2130            next_inlay_id: 0,
 2131            code_action_providers,
 2132            available_code_actions: None,
 2133            code_actions_task: None,
 2134            quick_selection_highlight_task: None,
 2135            debounced_selection_highlight_task: None,
 2136            document_highlights_task: None,
 2137            linked_editing_range_task: None,
 2138            pending_rename: None,
 2139            searchable: !is_minimap,
 2140            cursor_shape: EditorSettings::get_global(cx)
 2141                .cursor_shape
 2142                .unwrap_or_default(),
 2143            current_line_highlight: None,
 2144            autoindent_mode: Some(AutoindentMode::EachLine),
 2145            collapse_matches: false,
 2146            workspace: None,
 2147            input_enabled: !is_minimap,
 2148            use_modal_editing: full_mode,
 2149            read_only: is_minimap,
 2150            use_autoclose: true,
 2151            use_auto_surround: true,
 2152            auto_replace_emoji_shortcode: false,
 2153            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2154            leader_id: None,
 2155            remote_id: None,
 2156            hover_state: HoverState::default(),
 2157            pending_mouse_down: None,
 2158            hovered_link_state: None,
 2159            edit_prediction_provider: None,
 2160            active_edit_prediction: None,
 2161            stale_edit_prediction_in_menu: None,
 2162            edit_prediction_preview: EditPredictionPreview::Inactive {
 2163                released_too_fast: false,
 2164            },
 2165            inline_diagnostics_enabled: full_mode,
 2166            diagnostics_enabled: full_mode,
 2167            word_completions_enabled: full_mode,
 2168            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2169            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2170            gutter_hovered: false,
 2171            pixel_position_of_newest_cursor: None,
 2172            last_bounds: None,
 2173            last_position_map: None,
 2174            expect_bounds_change: None,
 2175            gutter_dimensions: GutterDimensions::default(),
 2176            style: None,
 2177            show_cursor_names: false,
 2178            hovered_cursors: HashMap::default(),
 2179            next_editor_action_id: EditorActionId::default(),
 2180            editor_actions: Rc::default(),
 2181            edit_predictions_hidden_for_vim_mode: false,
 2182            show_edit_predictions_override: None,
 2183            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2184            edit_prediction_settings: EditPredictionSettings::Disabled,
 2185            edit_prediction_indent_conflict: false,
 2186            edit_prediction_requires_modifier_in_indent_conflict: true,
 2187            custom_context_menu: None,
 2188            show_git_blame_gutter: false,
 2189            show_git_blame_inline: false,
 2190            show_selection_menu: None,
 2191            show_git_blame_inline_delay_task: None,
 2192            git_blame_inline_enabled: full_mode
 2193                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2194            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2195            serialize_dirty_buffers: !is_minimap
 2196                && ProjectSettings::get_global(cx)
 2197                    .session
 2198                    .restore_unsaved_buffers,
 2199            blame: None,
 2200            blame_subscription: None,
 2201            tasks: BTreeMap::default(),
 2202
 2203            breakpoint_store,
 2204            gutter_breakpoint_indicator: (None, None),
 2205            hovered_diff_hunk_row: None,
 2206            _subscriptions: (!is_minimap)
 2207                .then(|| {
 2208                    vec![
 2209                        cx.observe(&buffer, Self::on_buffer_changed),
 2210                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2211                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2212                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2213                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2214                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2215                        cx.observe_window_activation(window, |editor, window, cx| {
 2216                            let active = window.is_window_active();
 2217                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2218                                if active {
 2219                                    blink_manager.enable(cx);
 2220                                } else {
 2221                                    blink_manager.disable(cx);
 2222                                }
 2223                            });
 2224                            if active {
 2225                                editor.show_mouse_cursor(cx);
 2226                            }
 2227                        }),
 2228                    ]
 2229                })
 2230                .unwrap_or_default(),
 2231            tasks_update_task: None,
 2232            pull_diagnostics_task: Task::ready(()),
 2233            colors: None,
 2234            next_color_inlay_id: 0,
 2235            linked_edit_ranges: Default::default(),
 2236            in_project_search: false,
 2237            previous_search_ranges: None,
 2238            breadcrumb_header: None,
 2239            focused_block: None,
 2240            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2241            addons: HashMap::default(),
 2242            registered_buffers: HashMap::default(),
 2243            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2244            selection_mark_mode: false,
 2245            toggle_fold_multiple_buffers: Task::ready(()),
 2246            serialize_selections: Task::ready(()),
 2247            serialize_folds: Task::ready(()),
 2248            text_style_refinement: None,
 2249            load_diff_task: load_uncommitted_diff,
 2250            temporary_diff_override: false,
 2251            mouse_cursor_hidden: false,
 2252            minimap: None,
 2253            hide_mouse_mode: EditorSettings::get_global(cx)
 2254                .hide_mouse
 2255                .unwrap_or_default(),
 2256            change_list: ChangeList::new(),
 2257            mode,
 2258            selection_drag_state: SelectionDragState::None,
 2259            folding_newlines: Task::ready(()),
 2260            lookup_key: None,
 2261        };
 2262
 2263        if is_minimap {
 2264            return editor;
 2265        }
 2266
 2267        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2268            editor
 2269                ._subscriptions
 2270                .push(cx.observe(breakpoints, |_, _, cx| {
 2271                    cx.notify();
 2272                }));
 2273        }
 2274        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2275        editor._subscriptions.extend(project_subscriptions);
 2276
 2277        editor._subscriptions.push(cx.subscribe_in(
 2278            &cx.entity(),
 2279            window,
 2280            |editor, _, e: &EditorEvent, window, cx| match e {
 2281                EditorEvent::ScrollPositionChanged { local, .. } => {
 2282                    if *local {
 2283                        let new_anchor = editor.scroll_manager.anchor();
 2284                        let snapshot = editor.snapshot(window, cx);
 2285                        editor.update_restoration_data(cx, move |data| {
 2286                            data.scroll_position = (
 2287                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2288                                new_anchor.offset,
 2289                            );
 2290                        });
 2291                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2292                        editor.inline_blame_popover.take();
 2293                    }
 2294                }
 2295                EditorEvent::Edited { .. } => {
 2296                    if !vim_enabled(cx) {
 2297                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2298                        let pop_state = editor
 2299                            .change_list
 2300                            .last()
 2301                            .map(|previous| {
 2302                                previous.len() == selections.len()
 2303                                    && previous.iter().enumerate().all(|(ix, p)| {
 2304                                        p.to_display_point(&map).row()
 2305                                            == selections[ix].head().row()
 2306                                    })
 2307                            })
 2308                            .unwrap_or(false);
 2309                        let new_positions = selections
 2310                            .into_iter()
 2311                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2312                            .collect();
 2313                        editor
 2314                            .change_list
 2315                            .push_to_change_list(pop_state, new_positions);
 2316                    }
 2317                }
 2318                _ => (),
 2319            },
 2320        ));
 2321
 2322        if let Some(dap_store) = editor
 2323            .project
 2324            .as_ref()
 2325            .map(|project| project.read(cx).dap_store())
 2326        {
 2327            let weak_editor = cx.weak_entity();
 2328
 2329            editor
 2330                ._subscriptions
 2331                .push(
 2332                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2333                        let session_entity = cx.entity();
 2334                        weak_editor
 2335                            .update(cx, |editor, cx| {
 2336                                editor._subscriptions.push(
 2337                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2338                                );
 2339                            })
 2340                            .ok();
 2341                    }),
 2342                );
 2343
 2344            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2345                editor
 2346                    ._subscriptions
 2347                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2348            }
 2349        }
 2350
 2351        // skip adding the initial selection to selection history
 2352        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2353        editor.end_selection(window, cx);
 2354        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2355
 2356        editor.scroll_manager.show_scrollbars(window, cx);
 2357        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2358
 2359        if full_mode {
 2360            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2361            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2362
 2363            if editor.git_blame_inline_enabled {
 2364                editor.start_git_blame_inline(false, window, cx);
 2365            }
 2366
 2367            editor.go_to_active_debug_line(window, cx);
 2368
 2369            if let Some(buffer) = buffer.read(cx).as_singleton()
 2370                && let Some(project) = editor.project()
 2371            {
 2372                let handle = project.update(cx, |project, cx| {
 2373                    project.register_buffer_with_language_servers(&buffer, cx)
 2374                });
 2375                editor
 2376                    .registered_buffers
 2377                    .insert(buffer.read(cx).remote_id(), handle);
 2378            }
 2379
 2380            editor.minimap =
 2381                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2382            editor.colors = Some(LspColorData::new(cx));
 2383            editor.update_lsp_data(false, None, window, cx);
 2384        }
 2385
 2386        if editor.mode.is_full() {
 2387            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2388        }
 2389
 2390        editor
 2391    }
 2392
 2393    pub fn deploy_mouse_context_menu(
 2394        &mut self,
 2395        position: gpui::Point<Pixels>,
 2396        context_menu: Entity<ContextMenu>,
 2397        window: &mut Window,
 2398        cx: &mut Context<Self>,
 2399    ) {
 2400        self.mouse_context_menu = Some(MouseContextMenu::new(
 2401            self,
 2402            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2403            context_menu,
 2404            window,
 2405            cx,
 2406        ));
 2407    }
 2408
 2409    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2410        self.mouse_context_menu
 2411            .as_ref()
 2412            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2413    }
 2414
 2415    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2416        if self
 2417            .selections
 2418            .pending
 2419            .as_ref()
 2420            .is_some_and(|pending_selection| {
 2421                let snapshot = self.buffer().read(cx).snapshot(cx);
 2422                pending_selection
 2423                    .selection
 2424                    .range()
 2425                    .includes(range, &snapshot)
 2426            })
 2427        {
 2428            return true;
 2429        }
 2430
 2431        self.selections
 2432            .disjoint_in_range::<usize>(range.clone(), cx)
 2433            .into_iter()
 2434            .any(|selection| {
 2435                // This is needed to cover a corner case, if we just check for an existing
 2436                // selection in the fold range, having a cursor at the start of the fold
 2437                // marks it as selected. Non-empty selections don't cause this.
 2438                let length = selection.end - selection.start;
 2439                length > 0
 2440            })
 2441    }
 2442
 2443    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2444        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2445    }
 2446
 2447    fn key_context_internal(
 2448        &self,
 2449        has_active_edit_prediction: bool,
 2450        window: &Window,
 2451        cx: &App,
 2452    ) -> KeyContext {
 2453        let mut key_context = KeyContext::new_with_defaults();
 2454        key_context.add("Editor");
 2455        let mode = match self.mode {
 2456            EditorMode::SingleLine => "single_line",
 2457            EditorMode::AutoHeight { .. } => "auto_height",
 2458            EditorMode::Minimap { .. } => "minimap",
 2459            EditorMode::Full { .. } => "full",
 2460        };
 2461
 2462        if EditorSettings::jupyter_enabled(cx) {
 2463            key_context.add("jupyter");
 2464        }
 2465
 2466        key_context.set("mode", mode);
 2467        if self.pending_rename.is_some() {
 2468            key_context.add("renaming");
 2469        }
 2470
 2471        match self.context_menu.borrow().as_ref() {
 2472            Some(CodeContextMenu::Completions(menu)) => {
 2473                if menu.visible() {
 2474                    key_context.add("menu");
 2475                    key_context.add("showing_completions");
 2476                }
 2477            }
 2478            Some(CodeContextMenu::CodeActions(menu)) => {
 2479                if menu.visible() {
 2480                    key_context.add("menu");
 2481                    key_context.add("showing_code_actions")
 2482                }
 2483            }
 2484            None => {}
 2485        }
 2486
 2487        if self.signature_help_state.has_multiple_signatures() {
 2488            key_context.add("showing_signature_help");
 2489        }
 2490
 2491        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2492        if !self.focus_handle(cx).contains_focused(window, cx)
 2493            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2494        {
 2495            for addon in self.addons.values() {
 2496                addon.extend_key_context(&mut key_context, cx)
 2497            }
 2498        }
 2499
 2500        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2501            if let Some(extension) = singleton_buffer
 2502                .read(cx)
 2503                .file()
 2504                .and_then(|file| file.path().extension()?.to_str())
 2505            {
 2506                key_context.set("extension", extension.to_string());
 2507            }
 2508        } else {
 2509            key_context.add("multibuffer");
 2510        }
 2511
 2512        if has_active_edit_prediction {
 2513            if self.edit_prediction_in_conflict() {
 2514                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2515            } else {
 2516                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2517                key_context.add("copilot_suggestion");
 2518            }
 2519        }
 2520
 2521        if self.selection_mark_mode {
 2522            key_context.add("selection_mode");
 2523        }
 2524
 2525        key_context
 2526    }
 2527
 2528    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2529        if self.mouse_cursor_hidden {
 2530            self.mouse_cursor_hidden = false;
 2531            cx.notify();
 2532        }
 2533    }
 2534
 2535    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2536        let hide_mouse_cursor = match origin {
 2537            HideMouseCursorOrigin::TypingAction => {
 2538                matches!(
 2539                    self.hide_mouse_mode,
 2540                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2541                )
 2542            }
 2543            HideMouseCursorOrigin::MovementAction => {
 2544                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2545            }
 2546        };
 2547        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2548            self.mouse_cursor_hidden = hide_mouse_cursor;
 2549            cx.notify();
 2550        }
 2551    }
 2552
 2553    pub fn edit_prediction_in_conflict(&self) -> bool {
 2554        if !self.show_edit_predictions_in_menu() {
 2555            return false;
 2556        }
 2557
 2558        let showing_completions = self
 2559            .context_menu
 2560            .borrow()
 2561            .as_ref()
 2562            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2563
 2564        showing_completions
 2565            || self.edit_prediction_requires_modifier()
 2566            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2567            // bindings to insert tab characters.
 2568            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2569    }
 2570
 2571    pub fn accept_edit_prediction_keybind(
 2572        &self,
 2573        accept_partial: bool,
 2574        window: &Window,
 2575        cx: &App,
 2576    ) -> AcceptEditPredictionBinding {
 2577        let key_context = self.key_context_internal(true, window, cx);
 2578        let in_conflict = self.edit_prediction_in_conflict();
 2579
 2580        let bindings = if accept_partial {
 2581            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2582        } else {
 2583            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2584        };
 2585
 2586        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2587        // just the first one.
 2588        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2589            !in_conflict
 2590                || binding
 2591                    .keystrokes()
 2592                    .first()
 2593                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2594        }))
 2595    }
 2596
 2597    pub fn new_file(
 2598        workspace: &mut Workspace,
 2599        _: &workspace::NewFile,
 2600        window: &mut Window,
 2601        cx: &mut Context<Workspace>,
 2602    ) {
 2603        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2604            "Failed to create buffer",
 2605            window,
 2606            cx,
 2607            |e, _, _| match e.error_code() {
 2608                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2609                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2610                e.error_tag("required").unwrap_or("the latest version")
 2611            )),
 2612                _ => None,
 2613            },
 2614        );
 2615    }
 2616
 2617    pub fn new_in_workspace(
 2618        workspace: &mut Workspace,
 2619        window: &mut Window,
 2620        cx: &mut Context<Workspace>,
 2621    ) -> Task<Result<Entity<Editor>>> {
 2622        let project = workspace.project().clone();
 2623        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2624
 2625        cx.spawn_in(window, async move |workspace, cx| {
 2626            let buffer = create.await?;
 2627            workspace.update_in(cx, |workspace, window, cx| {
 2628                let editor =
 2629                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2630                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2631                editor
 2632            })
 2633        })
 2634    }
 2635
 2636    fn new_file_vertical(
 2637        workspace: &mut Workspace,
 2638        _: &workspace::NewFileSplitVertical,
 2639        window: &mut Window,
 2640        cx: &mut Context<Workspace>,
 2641    ) {
 2642        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2643    }
 2644
 2645    fn new_file_horizontal(
 2646        workspace: &mut Workspace,
 2647        _: &workspace::NewFileSplitHorizontal,
 2648        window: &mut Window,
 2649        cx: &mut Context<Workspace>,
 2650    ) {
 2651        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2652    }
 2653
 2654    fn new_file_in_direction(
 2655        workspace: &mut Workspace,
 2656        direction: SplitDirection,
 2657        window: &mut Window,
 2658        cx: &mut Context<Workspace>,
 2659    ) {
 2660        let project = workspace.project().clone();
 2661        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2662
 2663        cx.spawn_in(window, async move |workspace, cx| {
 2664            let buffer = create.await?;
 2665            workspace.update_in(cx, move |workspace, window, cx| {
 2666                workspace.split_item(
 2667                    direction,
 2668                    Box::new(
 2669                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2670                    ),
 2671                    window,
 2672                    cx,
 2673                )
 2674            })?;
 2675            anyhow::Ok(())
 2676        })
 2677        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2678            match e.error_code() {
 2679                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2680                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2681                e.error_tag("required").unwrap_or("the latest version")
 2682            )),
 2683                _ => None,
 2684            }
 2685        });
 2686    }
 2687
 2688    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2689        self.leader_id
 2690    }
 2691
 2692    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2693        &self.buffer
 2694    }
 2695
 2696    pub fn project(&self) -> Option<&Entity<Project>> {
 2697        self.project.as_ref()
 2698    }
 2699
 2700    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2701        self.workspace.as_ref()?.0.upgrade()
 2702    }
 2703
 2704    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2705        self.buffer().read(cx).title(cx)
 2706    }
 2707
 2708    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2709        let git_blame_gutter_max_author_length = self
 2710            .render_git_blame_gutter(cx)
 2711            .then(|| {
 2712                if let Some(blame) = self.blame.as_ref() {
 2713                    let max_author_length =
 2714                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2715                    Some(max_author_length)
 2716                } else {
 2717                    None
 2718                }
 2719            })
 2720            .flatten();
 2721
 2722        EditorSnapshot {
 2723            mode: self.mode.clone(),
 2724            show_gutter: self.show_gutter,
 2725            show_line_numbers: self.show_line_numbers,
 2726            show_git_diff_gutter: self.show_git_diff_gutter,
 2727            show_code_actions: self.show_code_actions,
 2728            show_runnables: self.show_runnables,
 2729            show_breakpoints: self.show_breakpoints,
 2730            git_blame_gutter_max_author_length,
 2731            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2732            placeholder_display_snapshot: self
 2733                .placeholder_display_map
 2734                .as_ref()
 2735                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2736            scroll_anchor: self.scroll_manager.anchor(),
 2737            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2738            is_focused: self.focus_handle.is_focused(window),
 2739            current_line_highlight: self
 2740                .current_line_highlight
 2741                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2742            gutter_hovered: self.gutter_hovered,
 2743        }
 2744    }
 2745
 2746    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2747        self.buffer.read(cx).language_at(point, cx)
 2748    }
 2749
 2750    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2751        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2752    }
 2753
 2754    pub fn active_excerpt(
 2755        &self,
 2756        cx: &App,
 2757    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2758        self.buffer
 2759            .read(cx)
 2760            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2761    }
 2762
 2763    pub fn mode(&self) -> &EditorMode {
 2764        &self.mode
 2765    }
 2766
 2767    pub fn set_mode(&mut self, mode: EditorMode) {
 2768        self.mode = mode;
 2769    }
 2770
 2771    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2772        self.collaboration_hub.as_deref()
 2773    }
 2774
 2775    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2776        self.collaboration_hub = Some(hub);
 2777    }
 2778
 2779    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2780        self.in_project_search = in_project_search;
 2781    }
 2782
 2783    pub fn set_custom_context_menu(
 2784        &mut self,
 2785        f: impl 'static
 2786        + Fn(
 2787            &mut Self,
 2788            DisplayPoint,
 2789            &mut Window,
 2790            &mut Context<Self>,
 2791        ) -> Option<Entity<ui::ContextMenu>>,
 2792    ) {
 2793        self.custom_context_menu = Some(Box::new(f))
 2794    }
 2795
 2796    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2797        self.completion_provider = provider;
 2798    }
 2799
 2800    #[cfg(any(test, feature = "test-support"))]
 2801    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2802        self.completion_provider.clone()
 2803    }
 2804
 2805    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2806        self.semantics_provider.clone()
 2807    }
 2808
 2809    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2810        self.semantics_provider = provider;
 2811    }
 2812
 2813    pub fn set_edit_prediction_provider<T>(
 2814        &mut self,
 2815        provider: Option<Entity<T>>,
 2816        window: &mut Window,
 2817        cx: &mut Context<Self>,
 2818    ) where
 2819        T: EditPredictionProvider,
 2820    {
 2821        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2822            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2823                if this.focus_handle.is_focused(window) {
 2824                    this.update_visible_edit_prediction(window, cx);
 2825                }
 2826            }),
 2827            provider: Arc::new(provider),
 2828        });
 2829        self.update_edit_prediction_settings(cx);
 2830        self.refresh_edit_prediction(false, false, window, cx);
 2831    }
 2832
 2833    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2834        self.placeholder_display_map
 2835            .as_ref()
 2836            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2837    }
 2838
 2839    pub fn set_placeholder_text(
 2840        &mut self,
 2841        placeholder_text: &str,
 2842        window: &mut Window,
 2843        cx: &mut Context<Self>,
 2844    ) {
 2845        let multibuffer = cx
 2846            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2847
 2848        let style = window.text_style();
 2849
 2850        self.placeholder_display_map = Some(cx.new(|cx| {
 2851            DisplayMap::new(
 2852                multibuffer,
 2853                style.font(),
 2854                style.font_size.to_pixels(window.rem_size()),
 2855                None,
 2856                FILE_HEADER_HEIGHT,
 2857                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2858                Default::default(),
 2859                DiagnosticSeverity::Off,
 2860                cx,
 2861            )
 2862        }));
 2863        cx.notify();
 2864    }
 2865
 2866    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2867        self.cursor_shape = cursor_shape;
 2868
 2869        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2870        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2871
 2872        cx.notify();
 2873    }
 2874
 2875    pub fn set_current_line_highlight(
 2876        &mut self,
 2877        current_line_highlight: Option<CurrentLineHighlight>,
 2878    ) {
 2879        self.current_line_highlight = current_line_highlight;
 2880    }
 2881
 2882    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2883        self.collapse_matches = collapse_matches;
 2884    }
 2885
 2886    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2887        let buffers = self.buffer.read(cx).all_buffers();
 2888        let Some(project) = self.project.as_ref() else {
 2889            return;
 2890        };
 2891        project.update(cx, |project, cx| {
 2892            for buffer in buffers {
 2893                self.registered_buffers
 2894                    .entry(buffer.read(cx).remote_id())
 2895                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2896            }
 2897        })
 2898    }
 2899
 2900    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2901        if self.collapse_matches {
 2902            return range.start..range.start;
 2903        }
 2904        range.clone()
 2905    }
 2906
 2907    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2908        if self.display_map.read(cx).clip_at_line_ends != clip {
 2909            self.display_map
 2910                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2911        }
 2912    }
 2913
 2914    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2915        self.input_enabled = input_enabled;
 2916    }
 2917
 2918    pub fn set_edit_predictions_hidden_for_vim_mode(
 2919        &mut self,
 2920        hidden: bool,
 2921        window: &mut Window,
 2922        cx: &mut Context<Self>,
 2923    ) {
 2924        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2925            self.edit_predictions_hidden_for_vim_mode = hidden;
 2926            if hidden {
 2927                self.update_visible_edit_prediction(window, cx);
 2928            } else {
 2929                self.refresh_edit_prediction(true, false, window, cx);
 2930            }
 2931        }
 2932    }
 2933
 2934    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2935        self.menu_edit_predictions_policy = value;
 2936    }
 2937
 2938    pub fn set_autoindent(&mut self, autoindent: bool) {
 2939        if autoindent {
 2940            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2941        } else {
 2942            self.autoindent_mode = None;
 2943        }
 2944    }
 2945
 2946    pub fn read_only(&self, cx: &App) -> bool {
 2947        self.read_only || self.buffer.read(cx).read_only()
 2948    }
 2949
 2950    pub fn set_read_only(&mut self, read_only: bool) {
 2951        self.read_only = read_only;
 2952    }
 2953
 2954    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2955        self.use_autoclose = autoclose;
 2956    }
 2957
 2958    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2959        self.use_auto_surround = auto_surround;
 2960    }
 2961
 2962    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2963        self.auto_replace_emoji_shortcode = auto_replace;
 2964    }
 2965
 2966    pub fn toggle_edit_predictions(
 2967        &mut self,
 2968        _: &ToggleEditPrediction,
 2969        window: &mut Window,
 2970        cx: &mut Context<Self>,
 2971    ) {
 2972        if self.show_edit_predictions_override.is_some() {
 2973            self.set_show_edit_predictions(None, window, cx);
 2974        } else {
 2975            let show_edit_predictions = !self.edit_predictions_enabled();
 2976            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2977        }
 2978    }
 2979
 2980    pub fn set_show_edit_predictions(
 2981        &mut self,
 2982        show_edit_predictions: Option<bool>,
 2983        window: &mut Window,
 2984        cx: &mut Context<Self>,
 2985    ) {
 2986        self.show_edit_predictions_override = show_edit_predictions;
 2987        self.update_edit_prediction_settings(cx);
 2988
 2989        if let Some(false) = show_edit_predictions {
 2990            self.discard_edit_prediction(false, cx);
 2991        } else {
 2992            self.refresh_edit_prediction(false, true, window, cx);
 2993        }
 2994    }
 2995
 2996    fn edit_predictions_disabled_in_scope(
 2997        &self,
 2998        buffer: &Entity<Buffer>,
 2999        buffer_position: language::Anchor,
 3000        cx: &App,
 3001    ) -> bool {
 3002        let snapshot = buffer.read(cx).snapshot();
 3003        let settings = snapshot.settings_at(buffer_position, cx);
 3004
 3005        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3006            return false;
 3007        };
 3008
 3009        scope.override_name().is_some_and(|scope_name| {
 3010            settings
 3011                .edit_predictions_disabled_in
 3012                .iter()
 3013                .any(|s| s == scope_name)
 3014        })
 3015    }
 3016
 3017    pub fn set_use_modal_editing(&mut self, to: bool) {
 3018        self.use_modal_editing = to;
 3019    }
 3020
 3021    pub fn use_modal_editing(&self) -> bool {
 3022        self.use_modal_editing
 3023    }
 3024
 3025    fn selections_did_change(
 3026        &mut self,
 3027        local: bool,
 3028        old_cursor_position: &Anchor,
 3029        effects: SelectionEffects,
 3030        window: &mut Window,
 3031        cx: &mut Context<Self>,
 3032    ) {
 3033        window.invalidate_character_coordinates();
 3034
 3035        // Copy selections to primary selection buffer
 3036        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3037        if local {
 3038            let selections = self.selections.all::<usize>(cx);
 3039            let buffer_handle = self.buffer.read(cx).read(cx);
 3040
 3041            let mut text = String::new();
 3042            for (index, selection) in selections.iter().enumerate() {
 3043                let text_for_selection = buffer_handle
 3044                    .text_for_range(selection.start..selection.end)
 3045                    .collect::<String>();
 3046
 3047                text.push_str(&text_for_selection);
 3048                if index != selections.len() - 1 {
 3049                    text.push('\n');
 3050                }
 3051            }
 3052
 3053            if !text.is_empty() {
 3054                cx.write_to_primary(ClipboardItem::new_string(text));
 3055            }
 3056        }
 3057
 3058        let selection_anchors = self.selections.disjoint_anchors();
 3059
 3060        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3061            self.buffer.update(cx, |buffer, cx| {
 3062                buffer.set_active_selections(
 3063                    &selection_anchors,
 3064                    self.selections.line_mode,
 3065                    self.cursor_shape,
 3066                    cx,
 3067                )
 3068            });
 3069        }
 3070        let display_map = self
 3071            .display_map
 3072            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3073        let buffer = &display_map.buffer_snapshot;
 3074        if self.selections.count() == 1 {
 3075            self.add_selections_state = None;
 3076        }
 3077        self.select_next_state = None;
 3078        self.select_prev_state = None;
 3079        self.select_syntax_node_history.try_clear();
 3080        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3081        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3082        self.take_rename(false, window, cx);
 3083
 3084        let newest_selection = self.selections.newest_anchor();
 3085        let new_cursor_position = newest_selection.head();
 3086        let selection_start = newest_selection.start;
 3087
 3088        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3089            self.push_to_nav_history(
 3090                *old_cursor_position,
 3091                Some(new_cursor_position.to_point(buffer)),
 3092                false,
 3093                effects.nav_history == Some(true),
 3094                cx,
 3095            );
 3096        }
 3097
 3098        if local {
 3099            if let Some(buffer_id) = new_cursor_position.buffer_id
 3100                && !self.registered_buffers.contains_key(&buffer_id)
 3101                && let Some(project) = self.project.as_ref()
 3102            {
 3103                project.update(cx, |project, cx| {
 3104                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3105                        return;
 3106                    };
 3107                    self.registered_buffers.insert(
 3108                        buffer_id,
 3109                        project.register_buffer_with_language_servers(&buffer, cx),
 3110                    );
 3111                })
 3112            }
 3113
 3114            let mut context_menu = self.context_menu.borrow_mut();
 3115            let completion_menu = match context_menu.as_ref() {
 3116                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3117                Some(CodeContextMenu::CodeActions(_)) => {
 3118                    *context_menu = None;
 3119                    None
 3120                }
 3121                None => None,
 3122            };
 3123            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3124            drop(context_menu);
 3125
 3126            if effects.completions
 3127                && let Some(completion_position) = completion_position
 3128            {
 3129                let start_offset = selection_start.to_offset(buffer);
 3130                let position_matches = start_offset == completion_position.to_offset(buffer);
 3131                let continue_showing = if position_matches {
 3132                    if self.snippet_stack.is_empty() {
 3133                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3134                    } else {
 3135                        // Snippet choices can be shown even when the cursor is in whitespace.
 3136                        // Dismissing the menu with actions like backspace is handled by
 3137                        // invalidation regions.
 3138                        true
 3139                    }
 3140                } else {
 3141                    false
 3142                };
 3143
 3144                if continue_showing {
 3145                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3146                } else {
 3147                    self.hide_context_menu(window, cx);
 3148                }
 3149            }
 3150
 3151            hide_hover(self, cx);
 3152
 3153            if old_cursor_position.to_display_point(&display_map).row()
 3154                != new_cursor_position.to_display_point(&display_map).row()
 3155            {
 3156                self.available_code_actions.take();
 3157            }
 3158            self.refresh_code_actions(window, cx);
 3159            self.refresh_document_highlights(cx);
 3160            self.refresh_selected_text_highlights(false, window, cx);
 3161            refresh_matching_bracket_highlights(self, window, cx);
 3162            self.update_visible_edit_prediction(window, cx);
 3163            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3164            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3165            self.inline_blame_popover.take();
 3166            if self.git_blame_inline_enabled {
 3167                self.start_inline_blame_timer(window, cx);
 3168            }
 3169        }
 3170
 3171        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3172        cx.emit(EditorEvent::SelectionsChanged { local });
 3173
 3174        let selections = &self.selections.disjoint;
 3175        if selections.len() == 1 {
 3176            cx.emit(SearchEvent::ActiveMatchChanged)
 3177        }
 3178        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3179            let inmemory_selections = selections
 3180                .iter()
 3181                .map(|s| {
 3182                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3183                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3184                })
 3185                .collect();
 3186            self.update_restoration_data(cx, |data| {
 3187                data.selections = inmemory_selections;
 3188            });
 3189
 3190            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3191                && let Some(workspace_id) =
 3192                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3193            {
 3194                let snapshot = self.buffer().read(cx).snapshot(cx);
 3195                let selections = selections.clone();
 3196                let background_executor = cx.background_executor().clone();
 3197                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3198                self.serialize_selections = cx.background_spawn(async move {
 3199                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3200                            let db_selections = selections
 3201                                .iter()
 3202                                .map(|selection| {
 3203                                    (
 3204                                        selection.start.to_offset(&snapshot),
 3205                                        selection.end.to_offset(&snapshot),
 3206                                    )
 3207                                })
 3208                                .collect();
 3209
 3210                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3211                                .await
 3212                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3213                                .log_err();
 3214                        });
 3215            }
 3216        }
 3217
 3218        cx.notify();
 3219    }
 3220
 3221    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3222        use text::ToOffset as _;
 3223        use text::ToPoint as _;
 3224
 3225        if self.mode.is_minimap()
 3226            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3227        {
 3228            return;
 3229        }
 3230
 3231        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3232            return;
 3233        };
 3234
 3235        let snapshot = singleton.read(cx).snapshot();
 3236        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3237            let display_snapshot = display_map.snapshot(cx);
 3238
 3239            display_snapshot
 3240                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3241                .map(|fold| {
 3242                    fold.range.start.text_anchor.to_point(&snapshot)
 3243                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3244                })
 3245                .collect()
 3246        });
 3247        self.update_restoration_data(cx, |data| {
 3248            data.folds = inmemory_folds;
 3249        });
 3250
 3251        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3252            return;
 3253        };
 3254        let background_executor = cx.background_executor().clone();
 3255        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3256        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3257            display_map
 3258                .snapshot(cx)
 3259                .folds_in_range(0..snapshot.len())
 3260                .map(|fold| {
 3261                    (
 3262                        fold.range.start.text_anchor.to_offset(&snapshot),
 3263                        fold.range.end.text_anchor.to_offset(&snapshot),
 3264                    )
 3265                })
 3266                .collect()
 3267        });
 3268        self.serialize_folds = cx.background_spawn(async move {
 3269            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3270            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3271                .await
 3272                .with_context(|| {
 3273                    format!(
 3274                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3275                    )
 3276                })
 3277                .log_err();
 3278        });
 3279    }
 3280
 3281    pub fn sync_selections(
 3282        &mut self,
 3283        other: Entity<Editor>,
 3284        cx: &mut Context<Self>,
 3285    ) -> gpui::Subscription {
 3286        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3287        self.selections.change_with(cx, |selections| {
 3288            selections.select_anchors(other_selections);
 3289        });
 3290
 3291        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3292            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3293                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3294                if other_selections.is_empty() {
 3295                    return;
 3296                }
 3297                this.selections.change_with(cx, |selections| {
 3298                    selections.select_anchors(other_selections);
 3299                });
 3300            }
 3301        });
 3302
 3303        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3304            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3305                let these_selections = this.selections.disjoint.to_vec();
 3306                if these_selections.is_empty() {
 3307                    return;
 3308                }
 3309                other.update(cx, |other_editor, cx| {
 3310                    other_editor.selections.change_with(cx, |selections| {
 3311                        selections.select_anchors(these_selections);
 3312                    })
 3313                });
 3314            }
 3315        });
 3316
 3317        Subscription::join(other_subscription, this_subscription)
 3318    }
 3319
 3320    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3321    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3322    /// effects of selection change occur at the end of the transaction.
 3323    pub fn change_selections<R>(
 3324        &mut self,
 3325        effects: SelectionEffects,
 3326        window: &mut Window,
 3327        cx: &mut Context<Self>,
 3328        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3329    ) -> R {
 3330        if let Some(state) = &mut self.deferred_selection_effects_state {
 3331            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3332            state.effects.completions = effects.completions;
 3333            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3334            let (changed, result) = self.selections.change_with(cx, change);
 3335            state.changed |= changed;
 3336            return result;
 3337        }
 3338        let mut state = DeferredSelectionEffectsState {
 3339            changed: false,
 3340            effects,
 3341            old_cursor_position: self.selections.newest_anchor().head(),
 3342            history_entry: SelectionHistoryEntry {
 3343                selections: self.selections.disjoint_anchors(),
 3344                select_next_state: self.select_next_state.clone(),
 3345                select_prev_state: self.select_prev_state.clone(),
 3346                add_selections_state: self.add_selections_state.clone(),
 3347            },
 3348        };
 3349        let (changed, result) = self.selections.change_with(cx, change);
 3350        state.changed = state.changed || changed;
 3351        if self.defer_selection_effects {
 3352            self.deferred_selection_effects_state = Some(state);
 3353        } else {
 3354            self.apply_selection_effects(state, window, cx);
 3355        }
 3356        result
 3357    }
 3358
 3359    /// Defers the effects of selection change, so that the effects of multiple calls to
 3360    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3361    /// to selection history and the state of popovers based on selection position aren't
 3362    /// erroneously updated.
 3363    pub fn with_selection_effects_deferred<R>(
 3364        &mut self,
 3365        window: &mut Window,
 3366        cx: &mut Context<Self>,
 3367        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3368    ) -> R {
 3369        let already_deferred = self.defer_selection_effects;
 3370        self.defer_selection_effects = true;
 3371        let result = update(self, window, cx);
 3372        if !already_deferred {
 3373            self.defer_selection_effects = false;
 3374            if let Some(state) = self.deferred_selection_effects_state.take() {
 3375                self.apply_selection_effects(state, window, cx);
 3376            }
 3377        }
 3378        result
 3379    }
 3380
 3381    fn apply_selection_effects(
 3382        &mut self,
 3383        state: DeferredSelectionEffectsState,
 3384        window: &mut Window,
 3385        cx: &mut Context<Self>,
 3386    ) {
 3387        if state.changed {
 3388            self.selection_history.push(state.history_entry);
 3389
 3390            if let Some(autoscroll) = state.effects.scroll {
 3391                self.request_autoscroll(autoscroll, cx);
 3392            }
 3393
 3394            let old_cursor_position = &state.old_cursor_position;
 3395
 3396            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3397
 3398            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3399                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3400            }
 3401        }
 3402    }
 3403
 3404    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3405    where
 3406        I: IntoIterator<Item = (Range<S>, T)>,
 3407        S: ToOffset,
 3408        T: Into<Arc<str>>,
 3409    {
 3410        if self.read_only(cx) {
 3411            return;
 3412        }
 3413
 3414        self.buffer
 3415            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3416    }
 3417
 3418    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3419    where
 3420        I: IntoIterator<Item = (Range<S>, T)>,
 3421        S: ToOffset,
 3422        T: Into<Arc<str>>,
 3423    {
 3424        if self.read_only(cx) {
 3425            return;
 3426        }
 3427
 3428        self.buffer.update(cx, |buffer, cx| {
 3429            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3430        });
 3431    }
 3432
 3433    pub fn edit_with_block_indent<I, S, T>(
 3434        &mut self,
 3435        edits: I,
 3436        original_indent_columns: Vec<Option<u32>>,
 3437        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(
 3449                edits,
 3450                Some(AutoindentMode::Block {
 3451                    original_indent_columns,
 3452                }),
 3453                cx,
 3454            )
 3455        });
 3456    }
 3457
 3458    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3459        self.hide_context_menu(window, cx);
 3460
 3461        match phase {
 3462            SelectPhase::Begin {
 3463                position,
 3464                add,
 3465                click_count,
 3466            } => self.begin_selection(position, add, click_count, window, cx),
 3467            SelectPhase::BeginColumnar {
 3468                position,
 3469                goal_column,
 3470                reset,
 3471                mode,
 3472            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3473            SelectPhase::Extend {
 3474                position,
 3475                click_count,
 3476            } => self.extend_selection(position, click_count, window, cx),
 3477            SelectPhase::Update {
 3478                position,
 3479                goal_column,
 3480                scroll_delta,
 3481            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3482            SelectPhase::End => self.end_selection(window, cx),
 3483        }
 3484    }
 3485
 3486    fn extend_selection(
 3487        &mut self,
 3488        position: DisplayPoint,
 3489        click_count: usize,
 3490        window: &mut Window,
 3491        cx: &mut Context<Self>,
 3492    ) {
 3493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3494        let tail = self.selections.newest::<usize>(cx).tail();
 3495        self.begin_selection(position, false, click_count, window, cx);
 3496
 3497        let position = position.to_offset(&display_map, Bias::Left);
 3498        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3499
 3500        let mut pending_selection = self
 3501            .selections
 3502            .pending_anchor()
 3503            .expect("extend_selection not called with pending selection");
 3504        if position >= tail {
 3505            pending_selection.start = tail_anchor;
 3506        } else {
 3507            pending_selection.end = tail_anchor;
 3508            pending_selection.reversed = true;
 3509        }
 3510
 3511        let mut pending_mode = self.selections.pending_mode().unwrap();
 3512        match &mut pending_mode {
 3513            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3514            _ => {}
 3515        }
 3516
 3517        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3518            SelectionEffects::scroll(Autoscroll::fit())
 3519        } else {
 3520            SelectionEffects::no_scroll()
 3521        };
 3522
 3523        self.change_selections(effects, window, cx, |s| {
 3524            s.set_pending(pending_selection, pending_mode)
 3525        });
 3526    }
 3527
 3528    fn begin_selection(
 3529        &mut self,
 3530        position: DisplayPoint,
 3531        add: bool,
 3532        click_count: usize,
 3533        window: &mut Window,
 3534        cx: &mut Context<Self>,
 3535    ) {
 3536        if !self.focus_handle.is_focused(window) {
 3537            self.last_focused_descendant = None;
 3538            window.focus(&self.focus_handle);
 3539        }
 3540
 3541        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3542        let buffer = &display_map.buffer_snapshot;
 3543        let position = display_map.clip_point(position, Bias::Left);
 3544
 3545        let start;
 3546        let end;
 3547        let mode;
 3548        let mut auto_scroll;
 3549        match click_count {
 3550            1 => {
 3551                start = buffer.anchor_before(position.to_point(&display_map));
 3552                end = start;
 3553                mode = SelectMode::Character;
 3554                auto_scroll = true;
 3555            }
 3556            2 => {
 3557                let position = display_map
 3558                    .clip_point(position, Bias::Left)
 3559                    .to_offset(&display_map, Bias::Left);
 3560                let (range, _) = buffer.surrounding_word(position, false);
 3561                start = buffer.anchor_before(range.start);
 3562                end = buffer.anchor_before(range.end);
 3563                mode = SelectMode::Word(start..end);
 3564                auto_scroll = true;
 3565            }
 3566            3 => {
 3567                let position = display_map
 3568                    .clip_point(position, Bias::Left)
 3569                    .to_point(&display_map);
 3570                let line_start = display_map.prev_line_boundary(position).0;
 3571                let next_line_start = buffer.clip_point(
 3572                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3573                    Bias::Left,
 3574                );
 3575                start = buffer.anchor_before(line_start);
 3576                end = buffer.anchor_before(next_line_start);
 3577                mode = SelectMode::Line(start..end);
 3578                auto_scroll = true;
 3579            }
 3580            _ => {
 3581                start = buffer.anchor_before(0);
 3582                end = buffer.anchor_before(buffer.len());
 3583                mode = SelectMode::All;
 3584                auto_scroll = false;
 3585            }
 3586        }
 3587        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3588
 3589        let point_to_delete: Option<usize> = {
 3590            let selected_points: Vec<Selection<Point>> =
 3591                self.selections.disjoint_in_range(start..end, cx);
 3592
 3593            if !add || click_count > 1 {
 3594                None
 3595            } else if !selected_points.is_empty() {
 3596                Some(selected_points[0].id)
 3597            } else {
 3598                let clicked_point_already_selected =
 3599                    self.selections.disjoint.iter().find(|selection| {
 3600                        selection.start.to_point(buffer) == start.to_point(buffer)
 3601                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3602                    });
 3603
 3604                clicked_point_already_selected.map(|selection| selection.id)
 3605            }
 3606        };
 3607
 3608        let selections_count = self.selections.count();
 3609        let effects = if auto_scroll {
 3610            SelectionEffects::default()
 3611        } else {
 3612            SelectionEffects::no_scroll()
 3613        };
 3614
 3615        self.change_selections(effects, window, cx, |s| {
 3616            if let Some(point_to_delete) = point_to_delete {
 3617                s.delete(point_to_delete);
 3618
 3619                if selections_count == 1 {
 3620                    s.set_pending_anchor_range(start..end, mode);
 3621                }
 3622            } else {
 3623                if !add {
 3624                    s.clear_disjoint();
 3625                }
 3626
 3627                s.set_pending_anchor_range(start..end, mode);
 3628            }
 3629        });
 3630    }
 3631
 3632    fn begin_columnar_selection(
 3633        &mut self,
 3634        position: DisplayPoint,
 3635        goal_column: u32,
 3636        reset: bool,
 3637        mode: ColumnarMode,
 3638        window: &mut Window,
 3639        cx: &mut Context<Self>,
 3640    ) {
 3641        if !self.focus_handle.is_focused(window) {
 3642            self.last_focused_descendant = None;
 3643            window.focus(&self.focus_handle);
 3644        }
 3645
 3646        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3647
 3648        if reset {
 3649            let pointer_position = display_map
 3650                .buffer_snapshot
 3651                .anchor_before(position.to_point(&display_map));
 3652
 3653            self.change_selections(
 3654                SelectionEffects::scroll(Autoscroll::newest()),
 3655                window,
 3656                cx,
 3657                |s| {
 3658                    s.clear_disjoint();
 3659                    s.set_pending_anchor_range(
 3660                        pointer_position..pointer_position,
 3661                        SelectMode::Character,
 3662                    );
 3663                },
 3664            );
 3665        };
 3666
 3667        let tail = self.selections.newest::<Point>(cx).tail();
 3668        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3669        self.columnar_selection_state = match mode {
 3670            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3671                selection_tail: selection_anchor,
 3672                display_point: if reset {
 3673                    if position.column() != goal_column {
 3674                        Some(DisplayPoint::new(position.row(), goal_column))
 3675                    } else {
 3676                        None
 3677                    }
 3678                } else {
 3679                    None
 3680                },
 3681            }),
 3682            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3683                selection_tail: selection_anchor,
 3684            }),
 3685        };
 3686
 3687        if !reset {
 3688            self.select_columns(position, goal_column, &display_map, window, cx);
 3689        }
 3690    }
 3691
 3692    fn update_selection(
 3693        &mut self,
 3694        position: DisplayPoint,
 3695        goal_column: u32,
 3696        scroll_delta: gpui::Point<f32>,
 3697        window: &mut Window,
 3698        cx: &mut Context<Self>,
 3699    ) {
 3700        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3701
 3702        if self.columnar_selection_state.is_some() {
 3703            self.select_columns(position, goal_column, &display_map, window, cx);
 3704        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3705            let buffer = &display_map.buffer_snapshot;
 3706            let head;
 3707            let tail;
 3708            let mode = self.selections.pending_mode().unwrap();
 3709            match &mode {
 3710                SelectMode::Character => {
 3711                    head = position.to_point(&display_map);
 3712                    tail = pending.tail().to_point(buffer);
 3713                }
 3714                SelectMode::Word(original_range) => {
 3715                    let offset = display_map
 3716                        .clip_point(position, Bias::Left)
 3717                        .to_offset(&display_map, Bias::Left);
 3718                    let original_range = original_range.to_offset(buffer);
 3719
 3720                    let head_offset = if buffer.is_inside_word(offset, false)
 3721                        || original_range.contains(&offset)
 3722                    {
 3723                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3724                        if word_range.start < original_range.start {
 3725                            word_range.start
 3726                        } else {
 3727                            word_range.end
 3728                        }
 3729                    } else {
 3730                        offset
 3731                    };
 3732
 3733                    head = head_offset.to_point(buffer);
 3734                    if head_offset <= original_range.start {
 3735                        tail = original_range.end.to_point(buffer);
 3736                    } else {
 3737                        tail = original_range.start.to_point(buffer);
 3738                    }
 3739                }
 3740                SelectMode::Line(original_range) => {
 3741                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3742
 3743                    let position = display_map
 3744                        .clip_point(position, Bias::Left)
 3745                        .to_point(&display_map);
 3746                    let line_start = display_map.prev_line_boundary(position).0;
 3747                    let next_line_start = buffer.clip_point(
 3748                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3749                        Bias::Left,
 3750                    );
 3751
 3752                    if line_start < original_range.start {
 3753                        head = line_start
 3754                    } else {
 3755                        head = next_line_start
 3756                    }
 3757
 3758                    if head <= original_range.start {
 3759                        tail = original_range.end;
 3760                    } else {
 3761                        tail = original_range.start;
 3762                    }
 3763                }
 3764                SelectMode::All => {
 3765                    return;
 3766                }
 3767            };
 3768
 3769            if head < tail {
 3770                pending.start = buffer.anchor_before(head);
 3771                pending.end = buffer.anchor_before(tail);
 3772                pending.reversed = true;
 3773            } else {
 3774                pending.start = buffer.anchor_before(tail);
 3775                pending.end = buffer.anchor_before(head);
 3776                pending.reversed = false;
 3777            }
 3778
 3779            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3780                s.set_pending(pending, mode);
 3781            });
 3782        } else {
 3783            log::error!("update_selection dispatched with no pending selection");
 3784            return;
 3785        }
 3786
 3787        self.apply_scroll_delta(scroll_delta, window, cx);
 3788        cx.notify();
 3789    }
 3790
 3791    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3792        self.columnar_selection_state.take();
 3793        if self.selections.pending_anchor().is_some() {
 3794            let selections = self.selections.all::<usize>(cx);
 3795            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3796                s.select(selections);
 3797                s.clear_pending();
 3798            });
 3799        }
 3800    }
 3801
 3802    fn select_columns(
 3803        &mut self,
 3804        head: DisplayPoint,
 3805        goal_column: u32,
 3806        display_map: &DisplaySnapshot,
 3807        window: &mut Window,
 3808        cx: &mut Context<Self>,
 3809    ) {
 3810        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3811            return;
 3812        };
 3813
 3814        let tail = match columnar_state {
 3815            ColumnarSelectionState::FromMouse {
 3816                selection_tail,
 3817                display_point,
 3818            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3819            ColumnarSelectionState::FromSelection { selection_tail } => {
 3820                selection_tail.to_display_point(display_map)
 3821            }
 3822        };
 3823
 3824        let start_row = cmp::min(tail.row(), head.row());
 3825        let end_row = cmp::max(tail.row(), head.row());
 3826        let start_column = cmp::min(tail.column(), goal_column);
 3827        let end_column = cmp::max(tail.column(), goal_column);
 3828        let reversed = start_column < tail.column();
 3829
 3830        let selection_ranges = (start_row.0..=end_row.0)
 3831            .map(DisplayRow)
 3832            .filter_map(|row| {
 3833                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3834                    || start_column <= display_map.line_len(row))
 3835                    && !display_map.is_block_line(row)
 3836                {
 3837                    let start = display_map
 3838                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3839                        .to_point(display_map);
 3840                    let end = display_map
 3841                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3842                        .to_point(display_map);
 3843                    if reversed {
 3844                        Some(end..start)
 3845                    } else {
 3846                        Some(start..end)
 3847                    }
 3848                } else {
 3849                    None
 3850                }
 3851            })
 3852            .collect::<Vec<_>>();
 3853
 3854        let ranges = match columnar_state {
 3855            ColumnarSelectionState::FromMouse { .. } => {
 3856                let mut non_empty_ranges = selection_ranges
 3857                    .iter()
 3858                    .filter(|selection_range| selection_range.start != selection_range.end)
 3859                    .peekable();
 3860                if non_empty_ranges.peek().is_some() {
 3861                    non_empty_ranges.cloned().collect()
 3862                } else {
 3863                    selection_ranges
 3864                }
 3865            }
 3866            _ => selection_ranges,
 3867        };
 3868
 3869        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3870            s.select_ranges(ranges);
 3871        });
 3872        cx.notify();
 3873    }
 3874
 3875    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3876        self.selections
 3877            .all_adjusted(cx)
 3878            .iter()
 3879            .any(|selection| !selection.is_empty())
 3880    }
 3881
 3882    pub fn has_pending_nonempty_selection(&self) -> bool {
 3883        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3884            Some(Selection { start, end, .. }) => start != end,
 3885            None => false,
 3886        };
 3887
 3888        pending_nonempty_selection
 3889            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3890    }
 3891
 3892    pub fn has_pending_selection(&self) -> bool {
 3893        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3894    }
 3895
 3896    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3897        self.selection_mark_mode = false;
 3898        self.selection_drag_state = SelectionDragState::None;
 3899
 3900        if self.clear_expanded_diff_hunks(cx) {
 3901            cx.notify();
 3902            return;
 3903        }
 3904        if self.dismiss_menus_and_popups(true, window, cx) {
 3905            return;
 3906        }
 3907
 3908        if self.mode.is_full()
 3909            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3910        {
 3911            return;
 3912        }
 3913
 3914        cx.propagate();
 3915    }
 3916
 3917    pub fn dismiss_menus_and_popups(
 3918        &mut self,
 3919        is_user_requested: bool,
 3920        window: &mut Window,
 3921        cx: &mut Context<Self>,
 3922    ) -> bool {
 3923        if self.take_rename(false, window, cx).is_some() {
 3924            return true;
 3925        }
 3926
 3927        if hide_hover(self, cx) {
 3928            return true;
 3929        }
 3930
 3931        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3932            return true;
 3933        }
 3934
 3935        if self.hide_context_menu(window, cx).is_some() {
 3936            return true;
 3937        }
 3938
 3939        if self.mouse_context_menu.take().is_some() {
 3940            return true;
 3941        }
 3942
 3943        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3944            return true;
 3945        }
 3946
 3947        if self.snippet_stack.pop().is_some() {
 3948            return true;
 3949        }
 3950
 3951        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3952            self.dismiss_diagnostics(cx);
 3953            return true;
 3954        }
 3955
 3956        false
 3957    }
 3958
 3959    fn linked_editing_ranges_for(
 3960        &self,
 3961        selection: Range<text::Anchor>,
 3962        cx: &App,
 3963    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3964        if self.linked_edit_ranges.is_empty() {
 3965            return None;
 3966        }
 3967        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3968            selection.end.buffer_id.and_then(|end_buffer_id| {
 3969                if selection.start.buffer_id != Some(end_buffer_id) {
 3970                    return None;
 3971                }
 3972                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3973                let snapshot = buffer.read(cx).snapshot();
 3974                self.linked_edit_ranges
 3975                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3976                    .map(|ranges| (ranges, snapshot, buffer))
 3977            })?;
 3978        use text::ToOffset as TO;
 3979        // find offset from the start of current range to current cursor position
 3980        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3981
 3982        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3983        let start_difference = start_offset - start_byte_offset;
 3984        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3985        let end_difference = end_offset - start_byte_offset;
 3986        // Current range has associated linked ranges.
 3987        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3988        for range in linked_ranges.iter() {
 3989            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3990            let end_offset = start_offset + end_difference;
 3991            let start_offset = start_offset + start_difference;
 3992            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3993                continue;
 3994            }
 3995            if self.selections.disjoint_anchor_ranges().any(|s| {
 3996                if s.start.buffer_id != selection.start.buffer_id
 3997                    || s.end.buffer_id != selection.end.buffer_id
 3998                {
 3999                    return false;
 4000                }
 4001                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4002                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4003            }) {
 4004                continue;
 4005            }
 4006            let start = buffer_snapshot.anchor_after(start_offset);
 4007            let end = buffer_snapshot.anchor_after(end_offset);
 4008            linked_edits
 4009                .entry(buffer.clone())
 4010                .or_default()
 4011                .push(start..end);
 4012        }
 4013        Some(linked_edits)
 4014    }
 4015
 4016    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4017        let text: Arc<str> = text.into();
 4018
 4019        if self.read_only(cx) {
 4020            return;
 4021        }
 4022
 4023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4024
 4025        let selections = self.selections.all_adjusted(cx);
 4026        let mut bracket_inserted = false;
 4027        let mut edits = Vec::new();
 4028        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4029        let mut new_selections = Vec::with_capacity(selections.len());
 4030        let mut new_autoclose_regions = Vec::new();
 4031        let snapshot = self.buffer.read(cx).read(cx);
 4032        let mut clear_linked_edit_ranges = false;
 4033
 4034        for (selection, autoclose_region) in
 4035            self.selections_with_autoclose_regions(selections, &snapshot)
 4036        {
 4037            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4038                // Determine if the inserted text matches the opening or closing
 4039                // bracket of any of this language's bracket pairs.
 4040                let mut bracket_pair = None;
 4041                let mut is_bracket_pair_start = false;
 4042                let mut is_bracket_pair_end = false;
 4043                if !text.is_empty() {
 4044                    let mut bracket_pair_matching_end = None;
 4045                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4046                    //  and they are removing the character that triggered IME popup.
 4047                    for (pair, enabled) in scope.brackets() {
 4048                        if !pair.close && !pair.surround {
 4049                            continue;
 4050                        }
 4051
 4052                        if enabled && pair.start.ends_with(text.as_ref()) {
 4053                            let prefix_len = pair.start.len() - text.len();
 4054                            let preceding_text_matches_prefix = prefix_len == 0
 4055                                || (selection.start.column >= (prefix_len as u32)
 4056                                    && snapshot.contains_str_at(
 4057                                        Point::new(
 4058                                            selection.start.row,
 4059                                            selection.start.column - (prefix_len as u32),
 4060                                        ),
 4061                                        &pair.start[..prefix_len],
 4062                                    ));
 4063                            if preceding_text_matches_prefix {
 4064                                bracket_pair = Some(pair.clone());
 4065                                is_bracket_pair_start = true;
 4066                                break;
 4067                            }
 4068                        }
 4069                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4070                        {
 4071                            // take first bracket pair matching end, but don't break in case a later bracket
 4072                            // pair matches start
 4073                            bracket_pair_matching_end = Some(pair.clone());
 4074                        }
 4075                    }
 4076                    if let Some(end) = bracket_pair_matching_end
 4077                        && bracket_pair.is_none()
 4078                    {
 4079                        bracket_pair = Some(end);
 4080                        is_bracket_pair_end = true;
 4081                    }
 4082                }
 4083
 4084                if let Some(bracket_pair) = bracket_pair {
 4085                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4086                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4087                    let auto_surround =
 4088                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4089                    if selection.is_empty() {
 4090                        if is_bracket_pair_start {
 4091                            // If the inserted text is a suffix of an opening bracket and the
 4092                            // selection is preceded by the rest of the opening bracket, then
 4093                            // insert the closing bracket.
 4094                            let following_text_allows_autoclose = snapshot
 4095                                .chars_at(selection.start)
 4096                                .next()
 4097                                .is_none_or(|c| scope.should_autoclose_before(c));
 4098
 4099                            let preceding_text_allows_autoclose = selection.start.column == 0
 4100                                || snapshot
 4101                                    .reversed_chars_at(selection.start)
 4102                                    .next()
 4103                                    .is_none_or(|c| {
 4104                                        bracket_pair.start != bracket_pair.end
 4105                                            || !snapshot
 4106                                                .char_classifier_at(selection.start)
 4107                                                .is_word(c)
 4108                                    });
 4109
 4110                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4111                                && bracket_pair.start.len() == 1
 4112                            {
 4113                                let target = bracket_pair.start.chars().next().unwrap();
 4114                                let current_line_count = snapshot
 4115                                    .reversed_chars_at(selection.start)
 4116                                    .take_while(|&c| c != '\n')
 4117                                    .filter(|&c| c == target)
 4118                                    .count();
 4119                                current_line_count % 2 == 1
 4120                            } else {
 4121                                false
 4122                            };
 4123
 4124                            if autoclose
 4125                                && bracket_pair.close
 4126                                && following_text_allows_autoclose
 4127                                && preceding_text_allows_autoclose
 4128                                && !is_closing_quote
 4129                            {
 4130                                let anchor = snapshot.anchor_before(selection.end);
 4131                                new_selections.push((selection.map(|_| anchor), text.len()));
 4132                                new_autoclose_regions.push((
 4133                                    anchor,
 4134                                    text.len(),
 4135                                    selection.id,
 4136                                    bracket_pair.clone(),
 4137                                ));
 4138                                edits.push((
 4139                                    selection.range(),
 4140                                    format!("{}{}", text, bracket_pair.end).into(),
 4141                                ));
 4142                                bracket_inserted = true;
 4143                                continue;
 4144                            }
 4145                        }
 4146
 4147                        if let Some(region) = autoclose_region {
 4148                            // If the selection is followed by an auto-inserted closing bracket,
 4149                            // then don't insert that closing bracket again; just move the selection
 4150                            // past the closing bracket.
 4151                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4152                                && text.as_ref() == region.pair.end.as_str()
 4153                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4154                            if should_skip {
 4155                                let anchor = snapshot.anchor_after(selection.end);
 4156                                new_selections
 4157                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4158                                continue;
 4159                            }
 4160                        }
 4161
 4162                        let always_treat_brackets_as_autoclosed = snapshot
 4163                            .language_settings_at(selection.start, cx)
 4164                            .always_treat_brackets_as_autoclosed;
 4165                        if always_treat_brackets_as_autoclosed
 4166                            && is_bracket_pair_end
 4167                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4168                        {
 4169                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4170                            // and the inserted text is a closing bracket and the selection is followed
 4171                            // by the closing bracket then move the selection past the closing bracket.
 4172                            let anchor = snapshot.anchor_after(selection.end);
 4173                            new_selections.push((selection.map(|_| anchor), text.len()));
 4174                            continue;
 4175                        }
 4176                    }
 4177                    // If an opening bracket is 1 character long and is typed while
 4178                    // text is selected, then surround that text with the bracket pair.
 4179                    else if auto_surround
 4180                        && bracket_pair.surround
 4181                        && is_bracket_pair_start
 4182                        && bracket_pair.start.chars().count() == 1
 4183                    {
 4184                        edits.push((selection.start..selection.start, text.clone()));
 4185                        edits.push((
 4186                            selection.end..selection.end,
 4187                            bracket_pair.end.as_str().into(),
 4188                        ));
 4189                        bracket_inserted = true;
 4190                        new_selections.push((
 4191                            Selection {
 4192                                id: selection.id,
 4193                                start: snapshot.anchor_after(selection.start),
 4194                                end: snapshot.anchor_before(selection.end),
 4195                                reversed: selection.reversed,
 4196                                goal: selection.goal,
 4197                            },
 4198                            0,
 4199                        ));
 4200                        continue;
 4201                    }
 4202                }
 4203            }
 4204
 4205            if self.auto_replace_emoji_shortcode
 4206                && selection.is_empty()
 4207                && text.as_ref().ends_with(':')
 4208                && let Some(possible_emoji_short_code) =
 4209                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4210                && !possible_emoji_short_code.is_empty()
 4211                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4212            {
 4213                let emoji_shortcode_start = Point::new(
 4214                    selection.start.row,
 4215                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4216                );
 4217
 4218                // Remove shortcode from buffer
 4219                edits.push((
 4220                    emoji_shortcode_start..selection.start,
 4221                    "".to_string().into(),
 4222                ));
 4223                new_selections.push((
 4224                    Selection {
 4225                        id: selection.id,
 4226                        start: snapshot.anchor_after(emoji_shortcode_start),
 4227                        end: snapshot.anchor_before(selection.start),
 4228                        reversed: selection.reversed,
 4229                        goal: selection.goal,
 4230                    },
 4231                    0,
 4232                ));
 4233
 4234                // Insert emoji
 4235                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4236                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4237                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4238
 4239                continue;
 4240            }
 4241
 4242            // If not handling any auto-close operation, then just replace the selected
 4243            // text with the given input and move the selection to the end of the
 4244            // newly inserted text.
 4245            let anchor = snapshot.anchor_after(selection.end);
 4246            if !self.linked_edit_ranges.is_empty() {
 4247                let start_anchor = snapshot.anchor_before(selection.start);
 4248
 4249                let is_word_char = text.chars().next().is_none_or(|char| {
 4250                    let classifier = snapshot
 4251                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4252                        .ignore_punctuation(true);
 4253                    classifier.is_word(char)
 4254                });
 4255
 4256                if is_word_char {
 4257                    if let Some(ranges) = self
 4258                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4259                    {
 4260                        for (buffer, edits) in ranges {
 4261                            linked_edits
 4262                                .entry(buffer.clone())
 4263                                .or_default()
 4264                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4265                        }
 4266                    }
 4267                } else {
 4268                    clear_linked_edit_ranges = true;
 4269                }
 4270            }
 4271
 4272            new_selections.push((selection.map(|_| anchor), 0));
 4273            edits.push((selection.start..selection.end, text.clone()));
 4274        }
 4275
 4276        drop(snapshot);
 4277
 4278        self.transact(window, cx, |this, window, cx| {
 4279            if clear_linked_edit_ranges {
 4280                this.linked_edit_ranges.clear();
 4281            }
 4282            let initial_buffer_versions =
 4283                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4284
 4285            this.buffer.update(cx, |buffer, cx| {
 4286                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4287            });
 4288            for (buffer, edits) in linked_edits {
 4289                buffer.update(cx, |buffer, cx| {
 4290                    let snapshot = buffer.snapshot();
 4291                    let edits = edits
 4292                        .into_iter()
 4293                        .map(|(range, text)| {
 4294                            use text::ToPoint as TP;
 4295                            let end_point = TP::to_point(&range.end, &snapshot);
 4296                            let start_point = TP::to_point(&range.start, &snapshot);
 4297                            (start_point..end_point, text)
 4298                        })
 4299                        .sorted_by_key(|(range, _)| range.start);
 4300                    buffer.edit(edits, None, cx);
 4301                })
 4302            }
 4303            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4304            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4305            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4306            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4307                .zip(new_selection_deltas)
 4308                .map(|(selection, delta)| Selection {
 4309                    id: selection.id,
 4310                    start: selection.start + delta,
 4311                    end: selection.end + delta,
 4312                    reversed: selection.reversed,
 4313                    goal: SelectionGoal::None,
 4314                })
 4315                .collect::<Vec<_>>();
 4316
 4317            let mut i = 0;
 4318            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4319                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4320                let start = map.buffer_snapshot.anchor_before(position);
 4321                let end = map.buffer_snapshot.anchor_after(position);
 4322                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4323                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4324                        Ordering::Less => i += 1,
 4325                        Ordering::Greater => break,
 4326                        Ordering::Equal => {
 4327                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4328                                Ordering::Less => i += 1,
 4329                                Ordering::Equal => break,
 4330                                Ordering::Greater => break,
 4331                            }
 4332                        }
 4333                    }
 4334                }
 4335                this.autoclose_regions.insert(
 4336                    i,
 4337                    AutocloseRegion {
 4338                        selection_id,
 4339                        range: start..end,
 4340                        pair,
 4341                    },
 4342                );
 4343            }
 4344
 4345            let had_active_edit_prediction = this.has_active_edit_prediction();
 4346            this.change_selections(
 4347                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4348                window,
 4349                cx,
 4350                |s| s.select(new_selections),
 4351            );
 4352
 4353            if !bracket_inserted
 4354                && let Some(on_type_format_task) =
 4355                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4356            {
 4357                on_type_format_task.detach_and_log_err(cx);
 4358            }
 4359
 4360            let editor_settings = EditorSettings::get_global(cx);
 4361            if bracket_inserted
 4362                && (editor_settings.auto_signature_help
 4363                    || editor_settings.show_signature_help_after_edits)
 4364            {
 4365                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4366            }
 4367
 4368            let trigger_in_words =
 4369                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4370            if this.hard_wrap.is_some() {
 4371                let latest: Range<Point> = this.selections.newest(cx).range();
 4372                if latest.is_empty()
 4373                    && this
 4374                        .buffer()
 4375                        .read(cx)
 4376                        .snapshot(cx)
 4377                        .line_len(MultiBufferRow(latest.start.row))
 4378                        == latest.start.column
 4379                {
 4380                    this.rewrap_impl(
 4381                        RewrapOptions {
 4382                            override_language_settings: true,
 4383                            preserve_existing_whitespace: true,
 4384                        },
 4385                        cx,
 4386                    )
 4387                }
 4388            }
 4389            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4390            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4391            this.refresh_edit_prediction(true, false, window, cx);
 4392            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4393        });
 4394    }
 4395
 4396    fn find_possible_emoji_shortcode_at_position(
 4397        snapshot: &MultiBufferSnapshot,
 4398        position: Point,
 4399    ) -> Option<String> {
 4400        let mut chars = Vec::new();
 4401        let mut found_colon = false;
 4402        for char in snapshot.reversed_chars_at(position).take(100) {
 4403            // Found a possible emoji shortcode in the middle of the buffer
 4404            if found_colon {
 4405                if char.is_whitespace() {
 4406                    chars.reverse();
 4407                    return Some(chars.iter().collect());
 4408                }
 4409                // If the previous character is not a whitespace, we are in the middle of a word
 4410                // and we only want to complete the shortcode if the word is made up of other emojis
 4411                let mut containing_word = String::new();
 4412                for ch in snapshot
 4413                    .reversed_chars_at(position)
 4414                    .skip(chars.len() + 1)
 4415                    .take(100)
 4416                {
 4417                    if ch.is_whitespace() {
 4418                        break;
 4419                    }
 4420                    containing_word.push(ch);
 4421                }
 4422                let containing_word = containing_word.chars().rev().collect::<String>();
 4423                if util::word_consists_of_emojis(containing_word.as_str()) {
 4424                    chars.reverse();
 4425                    return Some(chars.iter().collect());
 4426                }
 4427            }
 4428
 4429            if char.is_whitespace() || !char.is_ascii() {
 4430                return None;
 4431            }
 4432            if char == ':' {
 4433                found_colon = true;
 4434            } else {
 4435                chars.push(char);
 4436            }
 4437        }
 4438        // Found a possible emoji shortcode at the beginning of the buffer
 4439        chars.reverse();
 4440        Some(chars.iter().collect())
 4441    }
 4442
 4443    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4444        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4445        self.transact(window, cx, |this, window, cx| {
 4446            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4447                let selections = this.selections.all::<usize>(cx);
 4448                let multi_buffer = this.buffer.read(cx);
 4449                let buffer = multi_buffer.snapshot(cx);
 4450                selections
 4451                    .iter()
 4452                    .map(|selection| {
 4453                        let start_point = selection.start.to_point(&buffer);
 4454                        let mut existing_indent =
 4455                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4456                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4457                        let start = selection.start;
 4458                        let end = selection.end;
 4459                        let selection_is_empty = start == end;
 4460                        let language_scope = buffer.language_scope_at(start);
 4461                        let (
 4462                            comment_delimiter,
 4463                            doc_delimiter,
 4464                            insert_extra_newline,
 4465                            indent_on_newline,
 4466                            indent_on_extra_newline,
 4467                        ) = if let Some(language) = &language_scope {
 4468                            let mut insert_extra_newline =
 4469                                insert_extra_newline_brackets(&buffer, start..end, language)
 4470                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4471
 4472                            // Comment extension on newline is allowed only for cursor selections
 4473                            let comment_delimiter = maybe!({
 4474                                if !selection_is_empty {
 4475                                    return None;
 4476                                }
 4477
 4478                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4479                                    return None;
 4480                                }
 4481
 4482                                let delimiters = language.line_comment_prefixes();
 4483                                let max_len_of_delimiter =
 4484                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4485                                let (snapshot, range) =
 4486                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4487
 4488                                let num_of_whitespaces = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .take_while(|c| c.is_whitespace())
 4491                                    .count();
 4492                                let comment_candidate = snapshot
 4493                                    .chars_for_range(range.clone())
 4494                                    .skip(num_of_whitespaces)
 4495                                    .take(max_len_of_delimiter)
 4496                                    .collect::<String>();
 4497                                let (delimiter, trimmed_len) = delimiters
 4498                                    .iter()
 4499                                    .filter_map(|delimiter| {
 4500                                        let prefix = delimiter.trim_end();
 4501                                        if comment_candidate.starts_with(prefix) {
 4502                                            Some((delimiter, prefix.len()))
 4503                                        } else {
 4504                                            None
 4505                                        }
 4506                                    })
 4507                                    .max_by_key(|(_, len)| *len)?;
 4508
 4509                                if let Some(BlockCommentConfig {
 4510                                    start: block_start, ..
 4511                                }) = language.block_comment()
 4512                                {
 4513                                    let block_start_trimmed = block_start.trim_end();
 4514                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4515                                        let line_content = snapshot
 4516                                            .chars_for_range(range)
 4517                                            .skip(num_of_whitespaces)
 4518                                            .take(block_start_trimmed.len())
 4519                                            .collect::<String>();
 4520
 4521                                        if line_content.starts_with(block_start_trimmed) {
 4522                                            return None;
 4523                                        }
 4524                                    }
 4525                                }
 4526
 4527                                let cursor_is_placed_after_comment_marker =
 4528                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4529                                if cursor_is_placed_after_comment_marker {
 4530                                    Some(delimiter.clone())
 4531                                } else {
 4532                                    None
 4533                                }
 4534                            });
 4535
 4536                            let mut indent_on_newline = IndentSize::spaces(0);
 4537                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4538
 4539                            let doc_delimiter = maybe!({
 4540                                if !selection_is_empty {
 4541                                    return None;
 4542                                }
 4543
 4544                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4545                                    return None;
 4546                                }
 4547
 4548                                let BlockCommentConfig {
 4549                                    start: start_tag,
 4550                                    end: end_tag,
 4551                                    prefix: delimiter,
 4552                                    tab_size: len,
 4553                                } = language.documentation_comment()?;
 4554                                let is_within_block_comment = buffer
 4555                                    .language_scope_at(start_point)
 4556                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4557                                if !is_within_block_comment {
 4558                                    return None;
 4559                                }
 4560
 4561                                let (snapshot, range) =
 4562                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4563
 4564                                let num_of_whitespaces = snapshot
 4565                                    .chars_for_range(range.clone())
 4566                                    .take_while(|c| c.is_whitespace())
 4567                                    .count();
 4568
 4569                                // 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.
 4570                                let column = start_point.column;
 4571                                let cursor_is_after_start_tag = {
 4572                                    let start_tag_len = start_tag.len();
 4573                                    let start_tag_line = snapshot
 4574                                        .chars_for_range(range.clone())
 4575                                        .skip(num_of_whitespaces)
 4576                                        .take(start_tag_len)
 4577                                        .collect::<String>();
 4578                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4579                                        num_of_whitespaces + start_tag_len <= column as usize
 4580                                    } else {
 4581                                        false
 4582                                    }
 4583                                };
 4584
 4585                                let cursor_is_after_delimiter = {
 4586                                    let delimiter_trim = delimiter.trim_end();
 4587                                    let delimiter_line = snapshot
 4588                                        .chars_for_range(range.clone())
 4589                                        .skip(num_of_whitespaces)
 4590                                        .take(delimiter_trim.len())
 4591                                        .collect::<String>();
 4592                                    if delimiter_line.starts_with(delimiter_trim) {
 4593                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4594                                    } else {
 4595                                        false
 4596                                    }
 4597                                };
 4598
 4599                                let cursor_is_before_end_tag_if_exists = {
 4600                                    let mut char_position = 0u32;
 4601                                    let mut end_tag_offset = None;
 4602
 4603                                    'outer: for chunk in snapshot.text_for_range(range) {
 4604                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4605                                            let chars_before_match =
 4606                                                chunk[..byte_pos].chars().count() as u32;
 4607                                            end_tag_offset =
 4608                                                Some(char_position + chars_before_match);
 4609                                            break 'outer;
 4610                                        }
 4611                                        char_position += chunk.chars().count() as u32;
 4612                                    }
 4613
 4614                                    if let Some(end_tag_offset) = end_tag_offset {
 4615                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4616                                        if cursor_is_after_start_tag {
 4617                                            if cursor_is_before_end_tag {
 4618                                                insert_extra_newline = true;
 4619                                            }
 4620                                            let cursor_is_at_start_of_end_tag =
 4621                                                column == end_tag_offset;
 4622                                            if cursor_is_at_start_of_end_tag {
 4623                                                indent_on_extra_newline.len = *len;
 4624                                            }
 4625                                        }
 4626                                        cursor_is_before_end_tag
 4627                                    } else {
 4628                                        true
 4629                                    }
 4630                                };
 4631
 4632                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4633                                    && cursor_is_before_end_tag_if_exists
 4634                                {
 4635                                    if cursor_is_after_start_tag {
 4636                                        indent_on_newline.len = *len;
 4637                                    }
 4638                                    Some(delimiter.clone())
 4639                                } else {
 4640                                    None
 4641                                }
 4642                            });
 4643
 4644                            (
 4645                                comment_delimiter,
 4646                                doc_delimiter,
 4647                                insert_extra_newline,
 4648                                indent_on_newline,
 4649                                indent_on_extra_newline,
 4650                            )
 4651                        } else {
 4652                            (
 4653                                None,
 4654                                None,
 4655                                false,
 4656                                IndentSize::default(),
 4657                                IndentSize::default(),
 4658                            )
 4659                        };
 4660
 4661                        let prevent_auto_indent = doc_delimiter.is_some();
 4662                        let delimiter = comment_delimiter.or(doc_delimiter);
 4663
 4664                        let capacity_for_delimiter =
 4665                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4666                        let mut new_text = String::with_capacity(
 4667                            1 + capacity_for_delimiter
 4668                                + existing_indent.len as usize
 4669                                + indent_on_newline.len as usize
 4670                                + indent_on_extra_newline.len as usize,
 4671                        );
 4672                        new_text.push('\n');
 4673                        new_text.extend(existing_indent.chars());
 4674                        new_text.extend(indent_on_newline.chars());
 4675
 4676                        if let Some(delimiter) = &delimiter {
 4677                            new_text.push_str(delimiter);
 4678                        }
 4679
 4680                        if insert_extra_newline {
 4681                            new_text.push('\n');
 4682                            new_text.extend(existing_indent.chars());
 4683                            new_text.extend(indent_on_extra_newline.chars());
 4684                        }
 4685
 4686                        let anchor = buffer.anchor_after(end);
 4687                        let new_selection = selection.map(|_| anchor);
 4688                        (
 4689                            ((start..end, new_text), prevent_auto_indent),
 4690                            (insert_extra_newline, new_selection),
 4691                        )
 4692                    })
 4693                    .unzip()
 4694            };
 4695
 4696            let mut auto_indent_edits = Vec::new();
 4697            let mut edits = Vec::new();
 4698            for (edit, prevent_auto_indent) in edits_with_flags {
 4699                if prevent_auto_indent {
 4700                    edits.push(edit);
 4701                } else {
 4702                    auto_indent_edits.push(edit);
 4703                }
 4704            }
 4705            if !edits.is_empty() {
 4706                this.edit(edits, cx);
 4707            }
 4708            if !auto_indent_edits.is_empty() {
 4709                this.edit_with_autoindent(auto_indent_edits, cx);
 4710            }
 4711
 4712            let buffer = this.buffer.read(cx).snapshot(cx);
 4713            let new_selections = selection_info
 4714                .into_iter()
 4715                .map(|(extra_newline_inserted, new_selection)| {
 4716                    let mut cursor = new_selection.end.to_point(&buffer);
 4717                    if extra_newline_inserted {
 4718                        cursor.row -= 1;
 4719                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4720                    }
 4721                    new_selection.map(|_| cursor)
 4722                })
 4723                .collect();
 4724
 4725            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4726            this.refresh_edit_prediction(true, false, window, cx);
 4727        });
 4728    }
 4729
 4730    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4732
 4733        let buffer = self.buffer.read(cx);
 4734        let snapshot = buffer.snapshot(cx);
 4735
 4736        let mut edits = Vec::new();
 4737        let mut rows = Vec::new();
 4738
 4739        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4740            let cursor = selection.head();
 4741            let row = cursor.row;
 4742
 4743            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4744
 4745            let newline = "\n".to_string();
 4746            edits.push((start_of_line..start_of_line, newline));
 4747
 4748            rows.push(row + rows_inserted as u32);
 4749        }
 4750
 4751        self.transact(window, cx, |editor, window, cx| {
 4752            editor.edit(edits, cx);
 4753
 4754            editor.change_selections(Default::default(), window, cx, |s| {
 4755                let mut index = 0;
 4756                s.move_cursors_with(|map, _, _| {
 4757                    let row = rows[index];
 4758                    index += 1;
 4759
 4760                    let point = Point::new(row, 0);
 4761                    let boundary = map.next_line_boundary(point).1;
 4762                    let clipped = map.clip_point(boundary, Bias::Left);
 4763
 4764                    (clipped, SelectionGoal::None)
 4765                });
 4766            });
 4767
 4768            let mut indent_edits = Vec::new();
 4769            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4770            for row in rows {
 4771                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4772                for (row, indent) in indents {
 4773                    if indent.len == 0 {
 4774                        continue;
 4775                    }
 4776
 4777                    let text = match indent.kind {
 4778                        IndentKind::Space => " ".repeat(indent.len as usize),
 4779                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4780                    };
 4781                    let point = Point::new(row.0, 0);
 4782                    indent_edits.push((point..point, text));
 4783                }
 4784            }
 4785            editor.edit(indent_edits, cx);
 4786        });
 4787    }
 4788
 4789    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4791
 4792        let buffer = self.buffer.read(cx);
 4793        let snapshot = buffer.snapshot(cx);
 4794
 4795        let mut edits = Vec::new();
 4796        let mut rows = Vec::new();
 4797        let mut rows_inserted = 0;
 4798
 4799        for selection in self.selections.all_adjusted(cx) {
 4800            let cursor = selection.head();
 4801            let row = cursor.row;
 4802
 4803            let point = Point::new(row + 1, 0);
 4804            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4805
 4806            let newline = "\n".to_string();
 4807            edits.push((start_of_line..start_of_line, newline));
 4808
 4809            rows_inserted += 1;
 4810            rows.push(row + rows_inserted);
 4811        }
 4812
 4813        self.transact(window, cx, |editor, window, cx| {
 4814            editor.edit(edits, cx);
 4815
 4816            editor.change_selections(Default::default(), window, cx, |s| {
 4817                let mut index = 0;
 4818                s.move_cursors_with(|map, _, _| {
 4819                    let row = rows[index];
 4820                    index += 1;
 4821
 4822                    let point = Point::new(row, 0);
 4823                    let boundary = map.next_line_boundary(point).1;
 4824                    let clipped = map.clip_point(boundary, Bias::Left);
 4825
 4826                    (clipped, SelectionGoal::None)
 4827                });
 4828            });
 4829
 4830            let mut indent_edits = Vec::new();
 4831            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4832            for row in rows {
 4833                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4834                for (row, indent) in indents {
 4835                    if indent.len == 0 {
 4836                        continue;
 4837                    }
 4838
 4839                    let text = match indent.kind {
 4840                        IndentKind::Space => " ".repeat(indent.len as usize),
 4841                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4842                    };
 4843                    let point = Point::new(row.0, 0);
 4844                    indent_edits.push((point..point, text));
 4845                }
 4846            }
 4847            editor.edit(indent_edits, cx);
 4848        });
 4849    }
 4850
 4851    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4852        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4853            original_indent_columns: Vec::new(),
 4854        });
 4855        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4856    }
 4857
 4858    fn insert_with_autoindent_mode(
 4859        &mut self,
 4860        text: &str,
 4861        autoindent_mode: Option<AutoindentMode>,
 4862        window: &mut Window,
 4863        cx: &mut Context<Self>,
 4864    ) {
 4865        if self.read_only(cx) {
 4866            return;
 4867        }
 4868
 4869        let text: Arc<str> = text.into();
 4870        self.transact(window, cx, |this, window, cx| {
 4871            let old_selections = this.selections.all_adjusted(cx);
 4872            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4873                let anchors = {
 4874                    let snapshot = buffer.read(cx);
 4875                    old_selections
 4876                        .iter()
 4877                        .map(|s| {
 4878                            let anchor = snapshot.anchor_after(s.head());
 4879                            s.map(|_| anchor)
 4880                        })
 4881                        .collect::<Vec<_>>()
 4882                };
 4883                buffer.edit(
 4884                    old_selections
 4885                        .iter()
 4886                        .map(|s| (s.start..s.end, text.clone())),
 4887                    autoindent_mode,
 4888                    cx,
 4889                );
 4890                anchors
 4891            });
 4892
 4893            this.change_selections(Default::default(), window, cx, |s| {
 4894                s.select_anchors(selection_anchors);
 4895            });
 4896
 4897            cx.notify();
 4898        });
 4899    }
 4900
 4901    fn trigger_completion_on_input(
 4902        &mut self,
 4903        text: &str,
 4904        trigger_in_words: bool,
 4905        window: &mut Window,
 4906        cx: &mut Context<Self>,
 4907    ) {
 4908        let completions_source = self
 4909            .context_menu
 4910            .borrow()
 4911            .as_ref()
 4912            .and_then(|menu| match menu {
 4913                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4914                CodeContextMenu::CodeActions(_) => None,
 4915            });
 4916
 4917        match completions_source {
 4918            Some(CompletionsMenuSource::Words { .. }) => {
 4919                self.open_or_update_completions_menu(
 4920                    Some(CompletionsMenuSource::Words {
 4921                        ignore_threshold: false,
 4922                    }),
 4923                    None,
 4924                    window,
 4925                    cx,
 4926                );
 4927            }
 4928            Some(CompletionsMenuSource::Normal)
 4929            | Some(CompletionsMenuSource::SnippetChoices)
 4930            | None
 4931                if self.is_completion_trigger(
 4932                    text,
 4933                    trigger_in_words,
 4934                    completions_source.is_some(),
 4935                    cx,
 4936                ) =>
 4937            {
 4938                self.show_completions(
 4939                    &ShowCompletions {
 4940                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4941                    },
 4942                    window,
 4943                    cx,
 4944                )
 4945            }
 4946            _ => {
 4947                self.hide_context_menu(window, cx);
 4948            }
 4949        }
 4950    }
 4951
 4952    fn is_completion_trigger(
 4953        &self,
 4954        text: &str,
 4955        trigger_in_words: bool,
 4956        menu_is_open: bool,
 4957        cx: &mut Context<Self>,
 4958    ) -> bool {
 4959        let position = self.selections.newest_anchor().head();
 4960        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4961            return false;
 4962        };
 4963
 4964        if let Some(completion_provider) = &self.completion_provider {
 4965            completion_provider.is_completion_trigger(
 4966                &buffer,
 4967                position.text_anchor,
 4968                text,
 4969                trigger_in_words,
 4970                menu_is_open,
 4971                cx,
 4972            )
 4973        } else {
 4974            false
 4975        }
 4976    }
 4977
 4978    /// If any empty selections is touching the start of its innermost containing autoclose
 4979    /// region, expand it to select the brackets.
 4980    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4981        let selections = self.selections.all::<usize>(cx);
 4982        let buffer = self.buffer.read(cx).read(cx);
 4983        let new_selections = self
 4984            .selections_with_autoclose_regions(selections, &buffer)
 4985            .map(|(mut selection, region)| {
 4986                if !selection.is_empty() {
 4987                    return selection;
 4988                }
 4989
 4990                if let Some(region) = region {
 4991                    let mut range = region.range.to_offset(&buffer);
 4992                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4993                        range.start -= region.pair.start.len();
 4994                        if buffer.contains_str_at(range.start, &region.pair.start)
 4995                            && buffer.contains_str_at(range.end, &region.pair.end)
 4996                        {
 4997                            range.end += region.pair.end.len();
 4998                            selection.start = range.start;
 4999                            selection.end = range.end;
 5000
 5001                            return selection;
 5002                        }
 5003                    }
 5004                }
 5005
 5006                let always_treat_brackets_as_autoclosed = buffer
 5007                    .language_settings_at(selection.start, cx)
 5008                    .always_treat_brackets_as_autoclosed;
 5009
 5010                if !always_treat_brackets_as_autoclosed {
 5011                    return selection;
 5012                }
 5013
 5014                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5015                    for (pair, enabled) in scope.brackets() {
 5016                        if !enabled || !pair.close {
 5017                            continue;
 5018                        }
 5019
 5020                        if buffer.contains_str_at(selection.start, &pair.end) {
 5021                            let pair_start_len = pair.start.len();
 5022                            if buffer.contains_str_at(
 5023                                selection.start.saturating_sub(pair_start_len),
 5024                                &pair.start,
 5025                            ) {
 5026                                selection.start -= pair_start_len;
 5027                                selection.end += pair.end.len();
 5028
 5029                                return selection;
 5030                            }
 5031                        }
 5032                    }
 5033                }
 5034
 5035                selection
 5036            })
 5037            .collect();
 5038
 5039        drop(buffer);
 5040        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5041            selections.select(new_selections)
 5042        });
 5043    }
 5044
 5045    /// Iterate the given selections, and for each one, find the smallest surrounding
 5046    /// autoclose region. This uses the ordering of the selections and the autoclose
 5047    /// regions to avoid repeated comparisons.
 5048    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5049        &'a self,
 5050        selections: impl IntoIterator<Item = Selection<D>>,
 5051        buffer: &'a MultiBufferSnapshot,
 5052    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5053        let mut i = 0;
 5054        let mut regions = self.autoclose_regions.as_slice();
 5055        selections.into_iter().map(move |selection| {
 5056            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5057
 5058            let mut enclosing = None;
 5059            while let Some(pair_state) = regions.get(i) {
 5060                if pair_state.range.end.to_offset(buffer) < range.start {
 5061                    regions = &regions[i + 1..];
 5062                    i = 0;
 5063                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5064                    break;
 5065                } else {
 5066                    if pair_state.selection_id == selection.id {
 5067                        enclosing = Some(pair_state);
 5068                    }
 5069                    i += 1;
 5070                }
 5071            }
 5072
 5073            (selection, enclosing)
 5074        })
 5075    }
 5076
 5077    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5078    fn invalidate_autoclose_regions(
 5079        &mut self,
 5080        mut selections: &[Selection<Anchor>],
 5081        buffer: &MultiBufferSnapshot,
 5082    ) {
 5083        self.autoclose_regions.retain(|state| {
 5084            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5085                return false;
 5086            }
 5087
 5088            let mut i = 0;
 5089            while let Some(selection) = selections.get(i) {
 5090                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5091                    selections = &selections[1..];
 5092                    continue;
 5093                }
 5094                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5095                    break;
 5096                }
 5097                if selection.id == state.selection_id {
 5098                    return true;
 5099                } else {
 5100                    i += 1;
 5101                }
 5102            }
 5103            false
 5104        });
 5105    }
 5106
 5107    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5108        let offset = position.to_offset(buffer);
 5109        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5110        if offset > word_range.start && kind == Some(CharKind::Word) {
 5111            Some(
 5112                buffer
 5113                    .text_for_range(word_range.start..offset)
 5114                    .collect::<String>(),
 5115            )
 5116        } else {
 5117            None
 5118        }
 5119    }
 5120
 5121    pub fn toggle_inline_values(
 5122        &mut self,
 5123        _: &ToggleInlineValues,
 5124        _: &mut Window,
 5125        cx: &mut Context<Self>,
 5126    ) {
 5127        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5128
 5129        self.refresh_inline_values(cx);
 5130    }
 5131
 5132    pub fn toggle_inlay_hints(
 5133        &mut self,
 5134        _: &ToggleInlayHints,
 5135        _: &mut Window,
 5136        cx: &mut Context<Self>,
 5137    ) {
 5138        self.refresh_inlay_hints(
 5139            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5140            cx,
 5141        );
 5142    }
 5143
 5144    pub fn inlay_hints_enabled(&self) -> bool {
 5145        self.inlay_hint_cache.enabled
 5146    }
 5147
 5148    pub fn inline_values_enabled(&self) -> bool {
 5149        self.inline_value_cache.enabled
 5150    }
 5151
 5152    #[cfg(any(test, feature = "test-support"))]
 5153    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5154        self.display_map
 5155            .read(cx)
 5156            .current_inlays()
 5157            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5158            .cloned()
 5159            .collect()
 5160    }
 5161
 5162    #[cfg(any(test, feature = "test-support"))]
 5163    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5164        self.display_map
 5165            .read(cx)
 5166            .current_inlays()
 5167            .cloned()
 5168            .collect()
 5169    }
 5170
 5171    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5172        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5173            return;
 5174        }
 5175
 5176        let reason_description = reason.description();
 5177        let ignore_debounce = matches!(
 5178            reason,
 5179            InlayHintRefreshReason::SettingsChange(_)
 5180                | InlayHintRefreshReason::Toggle(_)
 5181                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5182                | InlayHintRefreshReason::ModifiersChanged(_)
 5183        );
 5184        let (invalidate_cache, required_languages) = match reason {
 5185            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5186                match self.inlay_hint_cache.modifiers_override(enabled) {
 5187                    Some(enabled) => {
 5188                        if enabled {
 5189                            (InvalidationStrategy::RefreshRequested, None)
 5190                        } else {
 5191                            self.splice_inlays(
 5192                                &self
 5193                                    .visible_inlay_hints(cx)
 5194                                    .iter()
 5195                                    .map(|inlay| inlay.id)
 5196                                    .collect::<Vec<InlayId>>(),
 5197                                Vec::new(),
 5198                                cx,
 5199                            );
 5200                            return;
 5201                        }
 5202                    }
 5203                    None => return,
 5204                }
 5205            }
 5206            InlayHintRefreshReason::Toggle(enabled) => {
 5207                if self.inlay_hint_cache.toggle(enabled) {
 5208                    if enabled {
 5209                        (InvalidationStrategy::RefreshRequested, None)
 5210                    } else {
 5211                        self.splice_inlays(
 5212                            &self
 5213                                .visible_inlay_hints(cx)
 5214                                .iter()
 5215                                .map(|inlay| inlay.id)
 5216                                .collect::<Vec<InlayId>>(),
 5217                            Vec::new(),
 5218                            cx,
 5219                        );
 5220                        return;
 5221                    }
 5222                } else {
 5223                    return;
 5224                }
 5225            }
 5226            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5227                match self.inlay_hint_cache.update_settings(
 5228                    &self.buffer,
 5229                    new_settings,
 5230                    self.visible_inlay_hints(cx),
 5231                    cx,
 5232                ) {
 5233                    ControlFlow::Break(Some(InlaySplice {
 5234                        to_remove,
 5235                        to_insert,
 5236                    })) => {
 5237                        self.splice_inlays(&to_remove, to_insert, cx);
 5238                        return;
 5239                    }
 5240                    ControlFlow::Break(None) => return,
 5241                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5242                }
 5243            }
 5244            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5245                if let Some(InlaySplice {
 5246                    to_remove,
 5247                    to_insert,
 5248                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5249                {
 5250                    self.splice_inlays(&to_remove, to_insert, cx);
 5251                }
 5252                self.display_map.update(cx, |display_map, _| {
 5253                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5254                });
 5255                return;
 5256            }
 5257            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5258            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5259                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5260            }
 5261            InlayHintRefreshReason::RefreshRequested => {
 5262                (InvalidationStrategy::RefreshRequested, None)
 5263            }
 5264        };
 5265
 5266        if let Some(InlaySplice {
 5267            to_remove,
 5268            to_insert,
 5269        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5270            reason_description,
 5271            self.visible_excerpts(required_languages.as_ref(), cx),
 5272            invalidate_cache,
 5273            ignore_debounce,
 5274            cx,
 5275        ) {
 5276            self.splice_inlays(&to_remove, to_insert, cx);
 5277        }
 5278    }
 5279
 5280    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5281        self.display_map
 5282            .read(cx)
 5283            .current_inlays()
 5284            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5285            .cloned()
 5286            .collect()
 5287    }
 5288
 5289    pub fn visible_excerpts(
 5290        &self,
 5291        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5292        cx: &mut Context<Editor>,
 5293    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5294        let Some(project) = self.project() else {
 5295            return HashMap::default();
 5296        };
 5297        let project = project.read(cx);
 5298        let multi_buffer = self.buffer().read(cx);
 5299        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5300        let multi_buffer_visible_start = self
 5301            .scroll_manager
 5302            .anchor()
 5303            .anchor
 5304            .to_point(&multi_buffer_snapshot);
 5305        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5306            multi_buffer_visible_start
 5307                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5308            Bias::Left,
 5309        );
 5310        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5311        multi_buffer_snapshot
 5312            .range_to_buffer_ranges(multi_buffer_visible_range)
 5313            .into_iter()
 5314            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5315            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5316                let buffer_file = project::File::from_dyn(buffer.file())?;
 5317                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5318                let worktree_entry = buffer_worktree
 5319                    .read(cx)
 5320                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5321                if worktree_entry.is_ignored {
 5322                    return None;
 5323                }
 5324
 5325                let language = buffer.language()?;
 5326                if let Some(restrict_to_languages) = restrict_to_languages
 5327                    && !restrict_to_languages.contains(language)
 5328                {
 5329                    return None;
 5330                }
 5331                Some((
 5332                    excerpt_id,
 5333                    (
 5334                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5335                        buffer.version().clone(),
 5336                        excerpt_visible_range,
 5337                    ),
 5338                ))
 5339            })
 5340            .collect()
 5341    }
 5342
 5343    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5344        TextLayoutDetails {
 5345            text_system: window.text_system().clone(),
 5346            editor_style: self.style.clone().unwrap(),
 5347            rem_size: window.rem_size(),
 5348            scroll_anchor: self.scroll_manager.anchor(),
 5349            visible_rows: self.visible_line_count(),
 5350            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5351        }
 5352    }
 5353
 5354    pub fn splice_inlays(
 5355        &self,
 5356        to_remove: &[InlayId],
 5357        to_insert: Vec<Inlay>,
 5358        cx: &mut Context<Self>,
 5359    ) {
 5360        self.display_map.update(cx, |display_map, cx| {
 5361            display_map.splice_inlays(to_remove, to_insert, cx)
 5362        });
 5363        cx.notify();
 5364    }
 5365
 5366    fn trigger_on_type_formatting(
 5367        &self,
 5368        input: String,
 5369        window: &mut Window,
 5370        cx: &mut Context<Self>,
 5371    ) -> Option<Task<Result<()>>> {
 5372        if input.len() != 1 {
 5373            return None;
 5374        }
 5375
 5376        let project = self.project()?;
 5377        let position = self.selections.newest_anchor().head();
 5378        let (buffer, buffer_position) = self
 5379            .buffer
 5380            .read(cx)
 5381            .text_anchor_for_position(position, cx)?;
 5382
 5383        let settings = language_settings::language_settings(
 5384            buffer
 5385                .read(cx)
 5386                .language_at(buffer_position)
 5387                .map(|l| l.name()),
 5388            buffer.read(cx).file(),
 5389            cx,
 5390        );
 5391        if !settings.use_on_type_format {
 5392            return None;
 5393        }
 5394
 5395        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5396        // hence we do LSP request & edit on host side only — add formats to host's history.
 5397        let push_to_lsp_host_history = true;
 5398        // If this is not the host, append its history with new edits.
 5399        let push_to_client_history = project.read(cx).is_via_collab();
 5400
 5401        let on_type_formatting = project.update(cx, |project, cx| {
 5402            project.on_type_format(
 5403                buffer.clone(),
 5404                buffer_position,
 5405                input,
 5406                push_to_lsp_host_history,
 5407                cx,
 5408            )
 5409        });
 5410        Some(cx.spawn_in(window, async move |editor, cx| {
 5411            if let Some(transaction) = on_type_formatting.await? {
 5412                if push_to_client_history {
 5413                    buffer
 5414                        .update(cx, |buffer, _| {
 5415                            buffer.push_transaction(transaction, Instant::now());
 5416                            buffer.finalize_last_transaction();
 5417                        })
 5418                        .ok();
 5419                }
 5420                editor.update(cx, |editor, cx| {
 5421                    editor.refresh_document_highlights(cx);
 5422                })?;
 5423            }
 5424            Ok(())
 5425        }))
 5426    }
 5427
 5428    pub fn show_word_completions(
 5429        &mut self,
 5430        _: &ShowWordCompletions,
 5431        window: &mut Window,
 5432        cx: &mut Context<Self>,
 5433    ) {
 5434        self.open_or_update_completions_menu(
 5435            Some(CompletionsMenuSource::Words {
 5436                ignore_threshold: true,
 5437            }),
 5438            None,
 5439            window,
 5440            cx,
 5441        );
 5442    }
 5443
 5444    pub fn show_completions(
 5445        &mut self,
 5446        options: &ShowCompletions,
 5447        window: &mut Window,
 5448        cx: &mut Context<Self>,
 5449    ) {
 5450        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5451    }
 5452
 5453    fn open_or_update_completions_menu(
 5454        &mut self,
 5455        requested_source: Option<CompletionsMenuSource>,
 5456        trigger: Option<&str>,
 5457        window: &mut Window,
 5458        cx: &mut Context<Self>,
 5459    ) {
 5460        if self.pending_rename.is_some() {
 5461            return;
 5462        }
 5463
 5464        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5465
 5466        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5467        // inserted and selected. To handle that case, the start of the selection is used so that
 5468        // the menu starts with all choices.
 5469        let position = self
 5470            .selections
 5471            .newest_anchor()
 5472            .start
 5473            .bias_right(&multibuffer_snapshot);
 5474        if position.diff_base_anchor.is_some() {
 5475            return;
 5476        }
 5477        let (buffer, buffer_position) =
 5478            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5479                output
 5480            } else {
 5481                return;
 5482            };
 5483        let buffer_snapshot = buffer.read(cx).snapshot();
 5484
 5485        let query: Option<Arc<String>> =
 5486            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5487
 5488        drop(multibuffer_snapshot);
 5489
 5490        let mut ignore_word_threshold = false;
 5491        let provider = match requested_source {
 5492            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5493            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5494                ignore_word_threshold = ignore_threshold;
 5495                None
 5496            }
 5497            Some(CompletionsMenuSource::SnippetChoices) => {
 5498                log::error!("bug: SnippetChoices requested_source is not handled");
 5499                None
 5500            }
 5501        };
 5502
 5503        let sort_completions = provider
 5504            .as_ref()
 5505            .is_some_and(|provider| provider.sort_completions());
 5506
 5507        let filter_completions = provider
 5508            .as_ref()
 5509            .is_none_or(|provider| provider.filter_completions());
 5510
 5511        let trigger_kind = match trigger {
 5512            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5513                CompletionTriggerKind::TRIGGER_CHARACTER
 5514            }
 5515            _ => CompletionTriggerKind::INVOKED,
 5516        };
 5517        let completion_context = CompletionContext {
 5518            trigger_character: trigger.and_then(|trigger| {
 5519                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5520                    Some(String::from(trigger))
 5521                } else {
 5522                    None
 5523                }
 5524            }),
 5525            trigger_kind,
 5526        };
 5527
 5528        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5529        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5530        // involve trigger chars, so this is skipped in that case.
 5531        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5532        {
 5533            let menu_is_open = matches!(
 5534                self.context_menu.borrow().as_ref(),
 5535                Some(CodeContextMenu::Completions(_))
 5536            );
 5537            if menu_is_open {
 5538                self.hide_context_menu(window, cx);
 5539            }
 5540        }
 5541
 5542        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5543            if filter_completions {
 5544                menu.filter(query.clone(), provider.clone(), window, cx);
 5545            }
 5546            // When `is_incomplete` is false, no need to re-query completions when the current query
 5547            // is a suffix of the initial query.
 5548            if !menu.is_incomplete {
 5549                // If the new query is a suffix of the old query (typing more characters) and
 5550                // the previous result was complete, the existing completions can be filtered.
 5551                //
 5552                // Note that this is always true for snippet completions.
 5553                let query_matches = match (&menu.initial_query, &query) {
 5554                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5555                    (None, _) => true,
 5556                    _ => false,
 5557                };
 5558                if query_matches {
 5559                    let position_matches = if menu.initial_position == position {
 5560                        true
 5561                    } else {
 5562                        let snapshot = self.buffer.read(cx).read(cx);
 5563                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5564                    };
 5565                    if position_matches {
 5566                        return;
 5567                    }
 5568                }
 5569            }
 5570        };
 5571
 5572        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5573            buffer_snapshot.surrounding_word(buffer_position, false)
 5574        {
 5575            let word_to_exclude = buffer_snapshot
 5576                .text_for_range(word_range.clone())
 5577                .collect::<String>();
 5578            (
 5579                buffer_snapshot.anchor_before(word_range.start)
 5580                    ..buffer_snapshot.anchor_after(buffer_position),
 5581                Some(word_to_exclude),
 5582            )
 5583        } else {
 5584            (buffer_position..buffer_position, None)
 5585        };
 5586
 5587        let language = buffer_snapshot
 5588            .language_at(buffer_position)
 5589            .map(|language| language.name());
 5590
 5591        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5592            .completions
 5593            .clone();
 5594
 5595        let show_completion_documentation = buffer_snapshot
 5596            .settings_at(buffer_position, cx)
 5597            .show_completion_documentation;
 5598
 5599        // The document can be large, so stay in reasonable bounds when searching for words,
 5600        // otherwise completion pop-up might be slow to appear.
 5601        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5602        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5603        let min_word_search = buffer_snapshot.clip_point(
 5604            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5605            Bias::Left,
 5606        );
 5607        let max_word_search = buffer_snapshot.clip_point(
 5608            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5609            Bias::Right,
 5610        );
 5611        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5612            ..buffer_snapshot.point_to_offset(max_word_search);
 5613
 5614        let skip_digits = query
 5615            .as_ref()
 5616            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5617
 5618        let omit_word_completions = !self.word_completions_enabled
 5619            || (!ignore_word_threshold
 5620                && match &query {
 5621                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5622                    None => completion_settings.words_min_length != 0,
 5623                });
 5624
 5625        let (mut words, provider_responses) = match &provider {
 5626            Some(provider) => {
 5627                let provider_responses = provider.completions(
 5628                    position.excerpt_id,
 5629                    &buffer,
 5630                    buffer_position,
 5631                    completion_context,
 5632                    window,
 5633                    cx,
 5634                );
 5635
 5636                let words = match (omit_word_completions, completion_settings.words) {
 5637                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5638                        Task::ready(BTreeMap::default())
 5639                    }
 5640                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5641                        .background_spawn(async move {
 5642                            buffer_snapshot.words_in_range(WordsQuery {
 5643                                fuzzy_contents: None,
 5644                                range: word_search_range,
 5645                                skip_digits,
 5646                            })
 5647                        }),
 5648                };
 5649
 5650                (words, provider_responses)
 5651            }
 5652            None => {
 5653                let words = if omit_word_completions {
 5654                    Task::ready(BTreeMap::default())
 5655                } else {
 5656                    cx.background_spawn(async move {
 5657                        buffer_snapshot.words_in_range(WordsQuery {
 5658                            fuzzy_contents: None,
 5659                            range: word_search_range,
 5660                            skip_digits,
 5661                        })
 5662                    })
 5663                };
 5664                (words, Task::ready(Ok(Vec::new())))
 5665            }
 5666        };
 5667
 5668        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5669
 5670        let id = post_inc(&mut self.next_completion_id);
 5671        let task = cx.spawn_in(window, async move |editor, cx| {
 5672            let Ok(()) = editor.update(cx, |this, _| {
 5673                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5674            }) else {
 5675                return;
 5676            };
 5677
 5678            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5679            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5680            let mut completions = Vec::new();
 5681            let mut is_incomplete = false;
 5682            let mut display_options: Option<CompletionDisplayOptions> = None;
 5683            if let Some(provider_responses) = provider_responses.await.log_err()
 5684                && !provider_responses.is_empty()
 5685            {
 5686                for response in provider_responses {
 5687                    completions.extend(response.completions);
 5688                    is_incomplete = is_incomplete || response.is_incomplete;
 5689                    match display_options.as_mut() {
 5690                        None => {
 5691                            display_options = Some(response.display_options);
 5692                        }
 5693                        Some(options) => options.merge(&response.display_options),
 5694                    }
 5695                }
 5696                if completion_settings.words == WordsCompletionMode::Fallback {
 5697                    words = Task::ready(BTreeMap::default());
 5698                }
 5699            }
 5700            let display_options = display_options.unwrap_or_default();
 5701
 5702            let mut words = words.await;
 5703            if let Some(word_to_exclude) = &word_to_exclude {
 5704                words.remove(word_to_exclude);
 5705            }
 5706            for lsp_completion in &completions {
 5707                words.remove(&lsp_completion.new_text);
 5708            }
 5709            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5710                replace_range: word_replace_range.clone(),
 5711                new_text: word.clone(),
 5712                label: CodeLabel::plain(word, None),
 5713                icon_path: None,
 5714                documentation: None,
 5715                source: CompletionSource::BufferWord {
 5716                    word_range,
 5717                    resolved: false,
 5718                },
 5719                insert_text_mode: Some(InsertTextMode::AS_IS),
 5720                confirm: None,
 5721            }));
 5722
 5723            let menu = if completions.is_empty() {
 5724                None
 5725            } else {
 5726                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5727                    let languages = editor
 5728                        .workspace
 5729                        .as_ref()
 5730                        .and_then(|(workspace, _)| workspace.upgrade())
 5731                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5732                    let menu = CompletionsMenu::new(
 5733                        id,
 5734                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5735                        sort_completions,
 5736                        show_completion_documentation,
 5737                        position,
 5738                        query.clone(),
 5739                        is_incomplete,
 5740                        buffer.clone(),
 5741                        completions.into(),
 5742                        display_options,
 5743                        snippet_sort_order,
 5744                        languages,
 5745                        language,
 5746                        cx,
 5747                    );
 5748
 5749                    let query = if filter_completions { query } else { None };
 5750                    let matches_task = if let Some(query) = query {
 5751                        menu.do_async_filtering(query, cx)
 5752                    } else {
 5753                        Task::ready(menu.unfiltered_matches())
 5754                    };
 5755                    (menu, matches_task)
 5756                }) else {
 5757                    return;
 5758                };
 5759
 5760                let matches = matches_task.await;
 5761
 5762                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5763                    // Newer menu already set, so exit.
 5764                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5765                        editor.context_menu.borrow().as_ref()
 5766                        && prev_menu.id > id
 5767                    {
 5768                        return;
 5769                    };
 5770
 5771                    // Only valid to take prev_menu because it the new menu is immediately set
 5772                    // below, or the menu is hidden.
 5773                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5774                        editor.context_menu.borrow_mut().take()
 5775                    {
 5776                        let position_matches =
 5777                            if prev_menu.initial_position == menu.initial_position {
 5778                                true
 5779                            } else {
 5780                                let snapshot = editor.buffer.read(cx).read(cx);
 5781                                prev_menu.initial_position.to_offset(&snapshot)
 5782                                    == menu.initial_position.to_offset(&snapshot)
 5783                            };
 5784                        if position_matches {
 5785                            // Preserve markdown cache before `set_filter_results` because it will
 5786                            // try to populate the documentation cache.
 5787                            menu.preserve_markdown_cache(prev_menu);
 5788                        }
 5789                    };
 5790
 5791                    menu.set_filter_results(matches, provider, window, cx);
 5792                }) else {
 5793                    return;
 5794                };
 5795
 5796                menu.visible().then_some(menu)
 5797            };
 5798
 5799            editor
 5800                .update_in(cx, |editor, window, cx| {
 5801                    if editor.focus_handle.is_focused(window)
 5802                        && let Some(menu) = menu
 5803                    {
 5804                        *editor.context_menu.borrow_mut() =
 5805                            Some(CodeContextMenu::Completions(menu));
 5806
 5807                        crate::hover_popover::hide_hover(editor, cx);
 5808                        if editor.show_edit_predictions_in_menu() {
 5809                            editor.update_visible_edit_prediction(window, cx);
 5810                        } else {
 5811                            editor.discard_edit_prediction(false, cx);
 5812                        }
 5813
 5814                        cx.notify();
 5815                        return;
 5816                    }
 5817
 5818                    if editor.completion_tasks.len() <= 1 {
 5819                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5820                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5821                        // If it was already hidden and we don't show edit predictions in the menu,
 5822                        // we should also show the edit prediction when available.
 5823                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5824                            editor.update_visible_edit_prediction(window, cx);
 5825                        }
 5826                    }
 5827                })
 5828                .ok();
 5829        });
 5830
 5831        self.completion_tasks.push((id, task));
 5832    }
 5833
 5834    #[cfg(feature = "test-support")]
 5835    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5836        let menu = self.context_menu.borrow();
 5837        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5838            let completions = menu.completions.borrow();
 5839            Some(completions.to_vec())
 5840        } else {
 5841            None
 5842        }
 5843    }
 5844
 5845    pub fn with_completions_menu_matching_id<R>(
 5846        &self,
 5847        id: CompletionId,
 5848        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5849    ) -> R {
 5850        let mut context_menu = self.context_menu.borrow_mut();
 5851        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5852            return f(None);
 5853        };
 5854        if completions_menu.id != id {
 5855            return f(None);
 5856        }
 5857        f(Some(completions_menu))
 5858    }
 5859
 5860    pub fn confirm_completion(
 5861        &mut self,
 5862        action: &ConfirmCompletion,
 5863        window: &mut Window,
 5864        cx: &mut Context<Self>,
 5865    ) -> Option<Task<Result<()>>> {
 5866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5867        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5868    }
 5869
 5870    pub fn confirm_completion_insert(
 5871        &mut self,
 5872        _: &ConfirmCompletionInsert,
 5873        window: &mut Window,
 5874        cx: &mut Context<Self>,
 5875    ) -> Option<Task<Result<()>>> {
 5876        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5877        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5878    }
 5879
 5880    pub fn confirm_completion_replace(
 5881        &mut self,
 5882        _: &ConfirmCompletionReplace,
 5883        window: &mut Window,
 5884        cx: &mut Context<Self>,
 5885    ) -> Option<Task<Result<()>>> {
 5886        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5887        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5888    }
 5889
 5890    pub fn compose_completion(
 5891        &mut self,
 5892        action: &ComposeCompletion,
 5893        window: &mut Window,
 5894        cx: &mut Context<Self>,
 5895    ) -> Option<Task<Result<()>>> {
 5896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5897        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5898    }
 5899
 5900    fn do_completion(
 5901        &mut self,
 5902        item_ix: Option<usize>,
 5903        intent: CompletionIntent,
 5904        window: &mut Window,
 5905        cx: &mut Context<Editor>,
 5906    ) -> Option<Task<Result<()>>> {
 5907        use language::ToOffset as _;
 5908
 5909        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5910        else {
 5911            return None;
 5912        };
 5913
 5914        let candidate_id = {
 5915            let entries = completions_menu.entries.borrow();
 5916            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5917            if self.show_edit_predictions_in_menu() {
 5918                self.discard_edit_prediction(true, cx);
 5919            }
 5920            mat.candidate_id
 5921        };
 5922
 5923        let completion = completions_menu
 5924            .completions
 5925            .borrow()
 5926            .get(candidate_id)?
 5927            .clone();
 5928        cx.stop_propagation();
 5929
 5930        let buffer_handle = completions_menu.buffer.clone();
 5931
 5932        let CompletionEdit {
 5933            new_text,
 5934            snippet,
 5935            replace_range,
 5936        } = process_completion_for_edit(
 5937            &completion,
 5938            intent,
 5939            &buffer_handle,
 5940            &completions_menu.initial_position.text_anchor,
 5941            cx,
 5942        );
 5943
 5944        let buffer = buffer_handle.read(cx);
 5945        let snapshot = self.buffer.read(cx).snapshot(cx);
 5946        let newest_anchor = self.selections.newest_anchor();
 5947        let replace_range_multibuffer = {
 5948            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5949            let multibuffer_anchor = snapshot
 5950                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5951                .unwrap()
 5952                ..snapshot
 5953                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5954                    .unwrap();
 5955            multibuffer_anchor.start.to_offset(&snapshot)
 5956                ..multibuffer_anchor.end.to_offset(&snapshot)
 5957        };
 5958        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5959            return None;
 5960        }
 5961
 5962        let old_text = buffer
 5963            .text_for_range(replace_range.clone())
 5964            .collect::<String>();
 5965        let lookbehind = newest_anchor
 5966            .start
 5967            .text_anchor
 5968            .to_offset(buffer)
 5969            .saturating_sub(replace_range.start);
 5970        let lookahead = replace_range
 5971            .end
 5972            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5973        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5974        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5975
 5976        let selections = self.selections.all::<usize>(cx);
 5977        let mut ranges = Vec::new();
 5978        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5979
 5980        for selection in &selections {
 5981            let range = if selection.id == newest_anchor.id {
 5982                replace_range_multibuffer.clone()
 5983            } else {
 5984                let mut range = selection.range();
 5985
 5986                // if prefix is present, don't duplicate it
 5987                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5988                    range.start = range.start.saturating_sub(lookbehind);
 5989
 5990                    // if suffix is also present, mimic the newest cursor and replace it
 5991                    if selection.id != newest_anchor.id
 5992                        && snapshot.contains_str_at(range.end, suffix)
 5993                    {
 5994                        range.end += lookahead;
 5995                    }
 5996                }
 5997                range
 5998            };
 5999
 6000            ranges.push(range.clone());
 6001
 6002            if !self.linked_edit_ranges.is_empty() {
 6003                let start_anchor = snapshot.anchor_before(range.start);
 6004                let end_anchor = snapshot.anchor_after(range.end);
 6005                if let Some(ranges) = self
 6006                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6007                {
 6008                    for (buffer, edits) in ranges {
 6009                        linked_edits
 6010                            .entry(buffer.clone())
 6011                            .or_default()
 6012                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6013                    }
 6014                }
 6015            }
 6016        }
 6017
 6018        let common_prefix_len = old_text
 6019            .chars()
 6020            .zip(new_text.chars())
 6021            .take_while(|(a, b)| a == b)
 6022            .map(|(a, _)| a.len_utf8())
 6023            .sum::<usize>();
 6024
 6025        cx.emit(EditorEvent::InputHandled {
 6026            utf16_range_to_replace: None,
 6027            text: new_text[common_prefix_len..].into(),
 6028        });
 6029
 6030        self.transact(window, cx, |editor, window, cx| {
 6031            if let Some(mut snippet) = snippet {
 6032                snippet.text = new_text.to_string();
 6033                editor
 6034                    .insert_snippet(&ranges, snippet, window, cx)
 6035                    .log_err();
 6036            } else {
 6037                editor.buffer.update(cx, |multi_buffer, cx| {
 6038                    let auto_indent = match completion.insert_text_mode {
 6039                        Some(InsertTextMode::AS_IS) => None,
 6040                        _ => editor.autoindent_mode.clone(),
 6041                    };
 6042                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6043                    multi_buffer.edit(edits, auto_indent, cx);
 6044                });
 6045            }
 6046            for (buffer, edits) in linked_edits {
 6047                buffer.update(cx, |buffer, cx| {
 6048                    let snapshot = buffer.snapshot();
 6049                    let edits = edits
 6050                        .into_iter()
 6051                        .map(|(range, text)| {
 6052                            use text::ToPoint as TP;
 6053                            let end_point = TP::to_point(&range.end, &snapshot);
 6054                            let start_point = TP::to_point(&range.start, &snapshot);
 6055                            (start_point..end_point, text)
 6056                        })
 6057                        .sorted_by_key(|(range, _)| range.start);
 6058                    buffer.edit(edits, None, cx);
 6059                })
 6060            }
 6061
 6062            editor.refresh_edit_prediction(true, false, window, cx);
 6063        });
 6064        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6065
 6066        let show_new_completions_on_confirm = completion
 6067            .confirm
 6068            .as_ref()
 6069            .is_some_and(|confirm| confirm(intent, window, cx));
 6070        if show_new_completions_on_confirm {
 6071            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6072        }
 6073
 6074        let provider = self.completion_provider.as_ref()?;
 6075        drop(completion);
 6076        let apply_edits = provider.apply_additional_edits_for_completion(
 6077            buffer_handle,
 6078            completions_menu.completions.clone(),
 6079            candidate_id,
 6080            true,
 6081            cx,
 6082        );
 6083
 6084        let editor_settings = EditorSettings::get_global(cx);
 6085        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6086            // After the code completion is finished, users often want to know what signatures are needed.
 6087            // so we should automatically call signature_help
 6088            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6089        }
 6090
 6091        Some(cx.foreground_executor().spawn(async move {
 6092            apply_edits.await?;
 6093            Ok(())
 6094        }))
 6095    }
 6096
 6097    pub fn toggle_code_actions(
 6098        &mut self,
 6099        action: &ToggleCodeActions,
 6100        window: &mut Window,
 6101        cx: &mut Context<Self>,
 6102    ) {
 6103        let quick_launch = action.quick_launch;
 6104        let mut context_menu = self.context_menu.borrow_mut();
 6105        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6106            if code_actions.deployed_from == action.deployed_from {
 6107                // Toggle if we're selecting the same one
 6108                *context_menu = None;
 6109                cx.notify();
 6110                return;
 6111            } else {
 6112                // Otherwise, clear it and start a new one
 6113                *context_menu = None;
 6114                cx.notify();
 6115            }
 6116        }
 6117        drop(context_menu);
 6118        let snapshot = self.snapshot(window, cx);
 6119        let deployed_from = action.deployed_from.clone();
 6120        let action = action.clone();
 6121        self.completion_tasks.clear();
 6122        self.discard_edit_prediction(false, cx);
 6123
 6124        let multibuffer_point = match &action.deployed_from {
 6125            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6126                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6127            }
 6128            _ => self.selections.newest::<Point>(cx).head(),
 6129        };
 6130        let Some((buffer, buffer_row)) = snapshot
 6131            .buffer_snapshot
 6132            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6133            .and_then(|(buffer_snapshot, range)| {
 6134                self.buffer()
 6135                    .read(cx)
 6136                    .buffer(buffer_snapshot.remote_id())
 6137                    .map(|buffer| (buffer, range.start.row))
 6138            })
 6139        else {
 6140            return;
 6141        };
 6142        let buffer_id = buffer.read(cx).remote_id();
 6143        let tasks = self
 6144            .tasks
 6145            .get(&(buffer_id, buffer_row))
 6146            .map(|t| Arc::new(t.to_owned()));
 6147
 6148        if !self.focus_handle.is_focused(window) {
 6149            return;
 6150        }
 6151        let project = self.project.clone();
 6152
 6153        let code_actions_task = match deployed_from {
 6154            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6155            _ => self.code_actions(buffer_row, window, cx),
 6156        };
 6157
 6158        let runnable_task = match deployed_from {
 6159            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6160            _ => {
 6161                let mut task_context_task = Task::ready(None);
 6162                if let Some(tasks) = &tasks
 6163                    && let Some(project) = project
 6164                {
 6165                    task_context_task =
 6166                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6167                }
 6168
 6169                cx.spawn_in(window, {
 6170                    let buffer = buffer.clone();
 6171                    async move |editor, cx| {
 6172                        let task_context = task_context_task.await;
 6173
 6174                        let resolved_tasks =
 6175                            tasks
 6176                                .zip(task_context.clone())
 6177                                .map(|(tasks, task_context)| ResolvedTasks {
 6178                                    templates: tasks.resolve(&task_context).collect(),
 6179                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6180                                        multibuffer_point.row,
 6181                                        tasks.column,
 6182                                    )),
 6183                                });
 6184                        let debug_scenarios = editor
 6185                            .update(cx, |editor, cx| {
 6186                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6187                            })?
 6188                            .await;
 6189                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6190                    }
 6191                })
 6192            }
 6193        };
 6194
 6195        cx.spawn_in(window, async move |editor, cx| {
 6196            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6197            let code_actions = code_actions_task.await;
 6198            let spawn_straight_away = quick_launch
 6199                && resolved_tasks
 6200                    .as_ref()
 6201                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6202                && code_actions
 6203                    .as_ref()
 6204                    .is_none_or(|actions| actions.is_empty())
 6205                && debug_scenarios.is_empty();
 6206
 6207            editor.update_in(cx, |editor, window, cx| {
 6208                crate::hover_popover::hide_hover(editor, cx);
 6209                let actions = CodeActionContents::new(
 6210                    resolved_tasks,
 6211                    code_actions,
 6212                    debug_scenarios,
 6213                    task_context.unwrap_or_default(),
 6214                );
 6215
 6216                // Don't show the menu if there are no actions available
 6217                if actions.is_empty() {
 6218                    cx.notify();
 6219                    return Task::ready(Ok(()));
 6220                }
 6221
 6222                *editor.context_menu.borrow_mut() =
 6223                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6224                        buffer,
 6225                        actions,
 6226                        selected_item: Default::default(),
 6227                        scroll_handle: UniformListScrollHandle::default(),
 6228                        deployed_from,
 6229                    }));
 6230                cx.notify();
 6231                if spawn_straight_away
 6232                    && let Some(task) = editor.confirm_code_action(
 6233                        &ConfirmCodeAction { item_ix: Some(0) },
 6234                        window,
 6235                        cx,
 6236                    )
 6237                {
 6238                    return task;
 6239                }
 6240
 6241                Task::ready(Ok(()))
 6242            })
 6243        })
 6244        .detach_and_log_err(cx);
 6245    }
 6246
 6247    fn debug_scenarios(
 6248        &mut self,
 6249        resolved_tasks: &Option<ResolvedTasks>,
 6250        buffer: &Entity<Buffer>,
 6251        cx: &mut App,
 6252    ) -> Task<Vec<task::DebugScenario>> {
 6253        maybe!({
 6254            let project = self.project()?;
 6255            let dap_store = project.read(cx).dap_store();
 6256            let mut scenarios = vec![];
 6257            let resolved_tasks = resolved_tasks.as_ref()?;
 6258            let buffer = buffer.read(cx);
 6259            let language = buffer.language()?;
 6260            let file = buffer.file();
 6261            let debug_adapter = language_settings(language.name().into(), file, cx)
 6262                .debuggers
 6263                .first()
 6264                .map(SharedString::from)
 6265                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6266
 6267            dap_store.update(cx, |dap_store, cx| {
 6268                for (_, task) in &resolved_tasks.templates {
 6269                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6270                        task.original_task().clone(),
 6271                        debug_adapter.clone().into(),
 6272                        task.display_label().to_owned().into(),
 6273                        cx,
 6274                    );
 6275                    scenarios.push(maybe_scenario);
 6276                }
 6277            });
 6278            Some(cx.background_spawn(async move {
 6279                futures::future::join_all(scenarios)
 6280                    .await
 6281                    .into_iter()
 6282                    .flatten()
 6283                    .collect::<Vec<_>>()
 6284            }))
 6285        })
 6286        .unwrap_or_else(|| Task::ready(vec![]))
 6287    }
 6288
 6289    fn code_actions(
 6290        &mut self,
 6291        buffer_row: u32,
 6292        window: &mut Window,
 6293        cx: &mut Context<Self>,
 6294    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6295        let mut task = self.code_actions_task.take();
 6296        cx.spawn_in(window, async move |editor, cx| {
 6297            while let Some(prev_task) = task {
 6298                prev_task.await.log_err();
 6299                task = editor
 6300                    .update(cx, |this, _| this.code_actions_task.take())
 6301                    .ok()?;
 6302            }
 6303
 6304            editor
 6305                .update(cx, |editor, cx| {
 6306                    editor
 6307                        .available_code_actions
 6308                        .clone()
 6309                        .and_then(|(location, code_actions)| {
 6310                            let snapshot = location.buffer.read(cx).snapshot();
 6311                            let point_range = location.range.to_point(&snapshot);
 6312                            let point_range = point_range.start.row..=point_range.end.row;
 6313                            if point_range.contains(&buffer_row) {
 6314                                Some(code_actions)
 6315                            } else {
 6316                                None
 6317                            }
 6318                        })
 6319                })
 6320                .ok()
 6321                .flatten()
 6322        })
 6323    }
 6324
 6325    pub fn confirm_code_action(
 6326        &mut self,
 6327        action: &ConfirmCodeAction,
 6328        window: &mut Window,
 6329        cx: &mut Context<Self>,
 6330    ) -> Option<Task<Result<()>>> {
 6331        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6332
 6333        let actions_menu =
 6334            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6335                menu
 6336            } else {
 6337                return None;
 6338            };
 6339
 6340        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6341        let action = actions_menu.actions.get(action_ix)?;
 6342        let title = action.label();
 6343        let buffer = actions_menu.buffer;
 6344        let workspace = self.workspace()?;
 6345
 6346        match action {
 6347            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6348                workspace.update(cx, |workspace, cx| {
 6349                    workspace.schedule_resolved_task(
 6350                        task_source_kind,
 6351                        resolved_task,
 6352                        false,
 6353                        window,
 6354                        cx,
 6355                    );
 6356
 6357                    Some(Task::ready(Ok(())))
 6358                })
 6359            }
 6360            CodeActionsItem::CodeAction {
 6361                excerpt_id,
 6362                action,
 6363                provider,
 6364            } => {
 6365                let apply_code_action =
 6366                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6367                let workspace = workspace.downgrade();
 6368                Some(cx.spawn_in(window, async move |editor, cx| {
 6369                    let project_transaction = apply_code_action.await?;
 6370                    Self::open_project_transaction(
 6371                        &editor,
 6372                        workspace,
 6373                        project_transaction,
 6374                        title,
 6375                        cx,
 6376                    )
 6377                    .await
 6378                }))
 6379            }
 6380            CodeActionsItem::DebugScenario(scenario) => {
 6381                let context = actions_menu.actions.context;
 6382
 6383                workspace.update(cx, |workspace, cx| {
 6384                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6385                    workspace.start_debug_session(
 6386                        scenario,
 6387                        context,
 6388                        Some(buffer),
 6389                        None,
 6390                        window,
 6391                        cx,
 6392                    );
 6393                });
 6394                Some(Task::ready(Ok(())))
 6395            }
 6396        }
 6397    }
 6398
 6399    pub async fn open_project_transaction(
 6400        editor: &WeakEntity<Editor>,
 6401        workspace: WeakEntity<Workspace>,
 6402        transaction: ProjectTransaction,
 6403        title: String,
 6404        cx: &mut AsyncWindowContext,
 6405    ) -> Result<()> {
 6406        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6407        cx.update(|_, cx| {
 6408            entries.sort_unstable_by_key(|(buffer, _)| {
 6409                buffer.read(cx).file().map(|f| f.path().clone())
 6410            });
 6411        })?;
 6412
 6413        // If the project transaction's edits are all contained within this editor, then
 6414        // avoid opening a new editor to display them.
 6415
 6416        if let Some((buffer, transaction)) = entries.first() {
 6417            if entries.len() == 1 {
 6418                let excerpt = editor.update(cx, |editor, cx| {
 6419                    editor
 6420                        .buffer()
 6421                        .read(cx)
 6422                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6423                })?;
 6424                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6425                    && excerpted_buffer == *buffer
 6426                {
 6427                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6428                        let excerpt_range = excerpt_range.to_offset(buffer);
 6429                        buffer
 6430                            .edited_ranges_for_transaction::<usize>(transaction)
 6431                            .all(|range| {
 6432                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6433                            })
 6434                    })?;
 6435
 6436                    if all_edits_within_excerpt {
 6437                        return Ok(());
 6438                    }
 6439                }
 6440            }
 6441        } else {
 6442            return Ok(());
 6443        }
 6444
 6445        let mut ranges_to_highlight = Vec::new();
 6446        let excerpt_buffer = cx.new(|cx| {
 6447            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6448            for (buffer_handle, transaction) in &entries {
 6449                let edited_ranges = buffer_handle
 6450                    .read(cx)
 6451                    .edited_ranges_for_transaction::<Point>(transaction)
 6452                    .collect::<Vec<_>>();
 6453                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6454                    PathKey::for_buffer(buffer_handle, cx),
 6455                    buffer_handle.clone(),
 6456                    edited_ranges,
 6457                    multibuffer_context_lines(cx),
 6458                    cx,
 6459                );
 6460
 6461                ranges_to_highlight.extend(ranges);
 6462            }
 6463            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6464            multibuffer
 6465        })?;
 6466
 6467        workspace.update_in(cx, |workspace, window, cx| {
 6468            let project = workspace.project().clone();
 6469            let editor =
 6470                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6471            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6472            editor.update(cx, |editor, cx| {
 6473                editor.highlight_background::<Self>(
 6474                    &ranges_to_highlight,
 6475                    |theme| theme.colors().editor_highlighted_line_background,
 6476                    cx,
 6477                );
 6478            });
 6479        })?;
 6480
 6481        Ok(())
 6482    }
 6483
 6484    pub fn clear_code_action_providers(&mut self) {
 6485        self.code_action_providers.clear();
 6486        self.available_code_actions.take();
 6487    }
 6488
 6489    pub fn add_code_action_provider(
 6490        &mut self,
 6491        provider: Rc<dyn CodeActionProvider>,
 6492        window: &mut Window,
 6493        cx: &mut Context<Self>,
 6494    ) {
 6495        if self
 6496            .code_action_providers
 6497            .iter()
 6498            .any(|existing_provider| existing_provider.id() == provider.id())
 6499        {
 6500            return;
 6501        }
 6502
 6503        self.code_action_providers.push(provider);
 6504        self.refresh_code_actions(window, cx);
 6505    }
 6506
 6507    pub fn remove_code_action_provider(
 6508        &mut self,
 6509        id: Arc<str>,
 6510        window: &mut Window,
 6511        cx: &mut Context<Self>,
 6512    ) {
 6513        self.code_action_providers
 6514            .retain(|provider| provider.id() != id);
 6515        self.refresh_code_actions(window, cx);
 6516    }
 6517
 6518    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6519        !self.code_action_providers.is_empty()
 6520            && EditorSettings::get_global(cx).toolbar.code_actions
 6521    }
 6522
 6523    pub fn has_available_code_actions(&self) -> bool {
 6524        self.available_code_actions
 6525            .as_ref()
 6526            .is_some_and(|(_, actions)| !actions.is_empty())
 6527    }
 6528
 6529    fn render_inline_code_actions(
 6530        &self,
 6531        icon_size: ui::IconSize,
 6532        display_row: DisplayRow,
 6533        is_active: bool,
 6534        cx: &mut Context<Self>,
 6535    ) -> AnyElement {
 6536        let show_tooltip = !self.context_menu_visible();
 6537        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6538            .icon_size(icon_size)
 6539            .shape(ui::IconButtonShape::Square)
 6540            .icon_color(ui::Color::Hidden)
 6541            .toggle_state(is_active)
 6542            .when(show_tooltip, |this| {
 6543                this.tooltip({
 6544                    let focus_handle = self.focus_handle.clone();
 6545                    move |window, cx| {
 6546                        Tooltip::for_action_in(
 6547                            "Toggle Code Actions",
 6548                            &ToggleCodeActions {
 6549                                deployed_from: None,
 6550                                quick_launch: false,
 6551                            },
 6552                            &focus_handle,
 6553                            window,
 6554                            cx,
 6555                        )
 6556                    }
 6557                })
 6558            })
 6559            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6560                window.focus(&editor.focus_handle(cx));
 6561                editor.toggle_code_actions(
 6562                    &crate::actions::ToggleCodeActions {
 6563                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6564                            display_row,
 6565                        )),
 6566                        quick_launch: false,
 6567                    },
 6568                    window,
 6569                    cx,
 6570                );
 6571            }))
 6572            .into_any_element()
 6573    }
 6574
 6575    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6576        &self.context_menu
 6577    }
 6578
 6579    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6580        let newest_selection = self.selections.newest_anchor().clone();
 6581        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6582        let buffer = self.buffer.read(cx);
 6583        if newest_selection.head().diff_base_anchor.is_some() {
 6584            return None;
 6585        }
 6586        let (start_buffer, start) =
 6587            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6588        let (end_buffer, end) =
 6589            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6590        if start_buffer != end_buffer {
 6591            return None;
 6592        }
 6593
 6594        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6595            cx.background_executor()
 6596                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6597                .await;
 6598
 6599            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6600                let providers = this.code_action_providers.clone();
 6601                let tasks = this
 6602                    .code_action_providers
 6603                    .iter()
 6604                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6605                    .collect::<Vec<_>>();
 6606                (providers, tasks)
 6607            })?;
 6608
 6609            let mut actions = Vec::new();
 6610            for (provider, provider_actions) in
 6611                providers.into_iter().zip(future::join_all(tasks).await)
 6612            {
 6613                if let Some(provider_actions) = provider_actions.log_err() {
 6614                    actions.extend(provider_actions.into_iter().map(|action| {
 6615                        AvailableCodeAction {
 6616                            excerpt_id: newest_selection.start.excerpt_id,
 6617                            action,
 6618                            provider: provider.clone(),
 6619                        }
 6620                    }));
 6621                }
 6622            }
 6623
 6624            this.update(cx, |this, cx| {
 6625                this.available_code_actions = if actions.is_empty() {
 6626                    None
 6627                } else {
 6628                    Some((
 6629                        Location {
 6630                            buffer: start_buffer,
 6631                            range: start..end,
 6632                        },
 6633                        actions.into(),
 6634                    ))
 6635                };
 6636                cx.notify();
 6637            })
 6638        }));
 6639        None
 6640    }
 6641
 6642    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6643        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6644            self.show_git_blame_inline = false;
 6645
 6646            self.show_git_blame_inline_delay_task =
 6647                Some(cx.spawn_in(window, async move |this, cx| {
 6648                    cx.background_executor().timer(delay).await;
 6649
 6650                    this.update(cx, |this, cx| {
 6651                        this.show_git_blame_inline = true;
 6652                        cx.notify();
 6653                    })
 6654                    .log_err();
 6655                }));
 6656        }
 6657    }
 6658
 6659    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6660        let snapshot = self.snapshot(window, cx);
 6661        let cursor = self.selections.newest::<Point>(cx).head();
 6662        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6663        else {
 6664            return;
 6665        };
 6666
 6667        let Some(blame) = self.blame.as_ref() else {
 6668            return;
 6669        };
 6670
 6671        let row_info = RowInfo {
 6672            buffer_id: Some(buffer.remote_id()),
 6673            buffer_row: Some(point.row),
 6674            ..Default::default()
 6675        };
 6676        let Some((buffer, blame_entry)) = blame
 6677            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6678            .flatten()
 6679        else {
 6680            return;
 6681        };
 6682
 6683        let anchor = self.selections.newest_anchor().head();
 6684        let position = self.to_pixel_point(anchor, &snapshot, window);
 6685        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6686            self.show_blame_popover(
 6687                buffer,
 6688                &blame_entry,
 6689                position + last_bounds.origin,
 6690                true,
 6691                cx,
 6692            );
 6693        };
 6694    }
 6695
 6696    fn show_blame_popover(
 6697        &mut self,
 6698        buffer: BufferId,
 6699        blame_entry: &BlameEntry,
 6700        position: gpui::Point<Pixels>,
 6701        ignore_timeout: bool,
 6702        cx: &mut Context<Self>,
 6703    ) {
 6704        if let Some(state) = &mut self.inline_blame_popover {
 6705            state.hide_task.take();
 6706        } else {
 6707            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6708            let blame_entry = blame_entry.clone();
 6709            let show_task = cx.spawn(async move |editor, cx| {
 6710                if !ignore_timeout {
 6711                    cx.background_executor()
 6712                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6713                        .await;
 6714                }
 6715                editor
 6716                    .update(cx, |editor, cx| {
 6717                        editor.inline_blame_popover_show_task.take();
 6718                        let Some(blame) = editor.blame.as_ref() else {
 6719                            return;
 6720                        };
 6721                        let blame = blame.read(cx);
 6722                        let details = blame.details_for_entry(buffer, &blame_entry);
 6723                        let markdown = cx.new(|cx| {
 6724                            Markdown::new(
 6725                                details
 6726                                    .as_ref()
 6727                                    .map(|message| message.message.clone())
 6728                                    .unwrap_or_default(),
 6729                                None,
 6730                                None,
 6731                                cx,
 6732                            )
 6733                        });
 6734                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6735                            position,
 6736                            hide_task: None,
 6737                            popover_bounds: None,
 6738                            popover_state: InlineBlamePopoverState {
 6739                                scroll_handle: ScrollHandle::new(),
 6740                                commit_message: details,
 6741                                markdown,
 6742                            },
 6743                            keyboard_grace: ignore_timeout,
 6744                        });
 6745                        cx.notify();
 6746                    })
 6747                    .ok();
 6748            });
 6749            self.inline_blame_popover_show_task = Some(show_task);
 6750        }
 6751    }
 6752
 6753    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6754        self.inline_blame_popover_show_task.take();
 6755        if let Some(state) = &mut self.inline_blame_popover {
 6756            let hide_task = cx.spawn(async move |editor, cx| {
 6757                cx.background_executor()
 6758                    .timer(std::time::Duration::from_millis(100))
 6759                    .await;
 6760                editor
 6761                    .update(cx, |editor, cx| {
 6762                        editor.inline_blame_popover.take();
 6763                        cx.notify();
 6764                    })
 6765                    .ok();
 6766            });
 6767            state.hide_task = Some(hide_task);
 6768        }
 6769    }
 6770
 6771    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6772        if self.pending_rename.is_some() {
 6773            return None;
 6774        }
 6775
 6776        let provider = self.semantics_provider.clone()?;
 6777        let buffer = self.buffer.read(cx);
 6778        let newest_selection = self.selections.newest_anchor().clone();
 6779        let cursor_position = newest_selection.head();
 6780        let (cursor_buffer, cursor_buffer_position) =
 6781            buffer.text_anchor_for_position(cursor_position, cx)?;
 6782        let (tail_buffer, tail_buffer_position) =
 6783            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6784        if cursor_buffer != tail_buffer {
 6785            return None;
 6786        }
 6787
 6788        let snapshot = cursor_buffer.read(cx).snapshot();
 6789        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6790        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6791        if start_word_range != end_word_range {
 6792            self.document_highlights_task.take();
 6793            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6794            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6795            return None;
 6796        }
 6797
 6798        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6799        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6800            cx.background_executor()
 6801                .timer(Duration::from_millis(debounce))
 6802                .await;
 6803
 6804            let highlights = if let Some(highlights) = cx
 6805                .update(|cx| {
 6806                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6807                })
 6808                .ok()
 6809                .flatten()
 6810            {
 6811                highlights.await.log_err()
 6812            } else {
 6813                None
 6814            };
 6815
 6816            if let Some(highlights) = highlights {
 6817                this.update(cx, |this, cx| {
 6818                    if this.pending_rename.is_some() {
 6819                        return;
 6820                    }
 6821
 6822                    let buffer = this.buffer.read(cx);
 6823                    if buffer
 6824                        .text_anchor_for_position(cursor_position, cx)
 6825                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6826                    {
 6827                        return;
 6828                    }
 6829
 6830                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6831                    let mut write_ranges = Vec::new();
 6832                    let mut read_ranges = Vec::new();
 6833                    for highlight in highlights {
 6834                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6835                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6836                        {
 6837                            let start = highlight
 6838                                .range
 6839                                .start
 6840                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6841                            let end = highlight
 6842                                .range
 6843                                .end
 6844                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6845                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6846                                continue;
 6847                            }
 6848
 6849                            let range = Anchor {
 6850                                buffer_id: Some(buffer_id),
 6851                                excerpt_id,
 6852                                text_anchor: start,
 6853                                diff_base_anchor: None,
 6854                            }..Anchor {
 6855                                buffer_id: Some(buffer_id),
 6856                                excerpt_id,
 6857                                text_anchor: end,
 6858                                diff_base_anchor: None,
 6859                            };
 6860                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6861                                write_ranges.push(range);
 6862                            } else {
 6863                                read_ranges.push(range);
 6864                            }
 6865                        }
 6866                    }
 6867
 6868                    this.highlight_background::<DocumentHighlightRead>(
 6869                        &read_ranges,
 6870                        |theme| theme.colors().editor_document_highlight_read_background,
 6871                        cx,
 6872                    );
 6873                    this.highlight_background::<DocumentHighlightWrite>(
 6874                        &write_ranges,
 6875                        |theme| theme.colors().editor_document_highlight_write_background,
 6876                        cx,
 6877                    );
 6878                    cx.notify();
 6879                })
 6880                .log_err();
 6881            }
 6882        }));
 6883        None
 6884    }
 6885
 6886    fn prepare_highlight_query_from_selection(
 6887        &mut self,
 6888        cx: &mut Context<Editor>,
 6889    ) -> Option<(String, Range<Anchor>)> {
 6890        if matches!(self.mode, EditorMode::SingleLine) {
 6891            return None;
 6892        }
 6893        if !EditorSettings::get_global(cx).selection_highlight {
 6894            return None;
 6895        }
 6896        if self.selections.count() != 1 || self.selections.line_mode {
 6897            return None;
 6898        }
 6899        let selection = self.selections.newest::<Point>(cx);
 6900        if selection.is_empty() || selection.start.row != selection.end.row {
 6901            return None;
 6902        }
 6903        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6904        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6905        let query = multi_buffer_snapshot
 6906            .text_for_range(selection_anchor_range.clone())
 6907            .collect::<String>();
 6908        if query.trim().is_empty() {
 6909            return None;
 6910        }
 6911        Some((query, selection_anchor_range))
 6912    }
 6913
 6914    fn update_selection_occurrence_highlights(
 6915        &mut self,
 6916        query_text: String,
 6917        query_range: Range<Anchor>,
 6918        multi_buffer_range_to_query: Range<Point>,
 6919        use_debounce: bool,
 6920        window: &mut Window,
 6921        cx: &mut Context<Editor>,
 6922    ) -> Task<()> {
 6923        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6924        cx.spawn_in(window, async move |editor, cx| {
 6925            if use_debounce {
 6926                cx.background_executor()
 6927                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6928                    .await;
 6929            }
 6930            let match_task = cx.background_spawn(async move {
 6931                let buffer_ranges = multi_buffer_snapshot
 6932                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6933                    .into_iter()
 6934                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6935                let mut match_ranges = Vec::new();
 6936                let Ok(regex) = project::search::SearchQuery::text(
 6937                    query_text.clone(),
 6938                    false,
 6939                    false,
 6940                    false,
 6941                    Default::default(),
 6942                    Default::default(),
 6943                    false,
 6944                    None,
 6945                ) else {
 6946                    return Vec::default();
 6947                };
 6948                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6949                    match_ranges.extend(
 6950                        regex
 6951                            .search(buffer_snapshot, Some(search_range.clone()))
 6952                            .await
 6953                            .into_iter()
 6954                            .filter_map(|match_range| {
 6955                                let match_start = buffer_snapshot
 6956                                    .anchor_after(search_range.start + match_range.start);
 6957                                let match_end = buffer_snapshot
 6958                                    .anchor_before(search_range.start + match_range.end);
 6959                                let match_anchor_range = Anchor::range_in_buffer(
 6960                                    excerpt_id,
 6961                                    buffer_snapshot.remote_id(),
 6962                                    match_start..match_end,
 6963                                );
 6964                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6965                            }),
 6966                    );
 6967                }
 6968                match_ranges
 6969            });
 6970            let match_ranges = match_task.await;
 6971            editor
 6972                .update_in(cx, |editor, _, cx| {
 6973                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6974                    if !match_ranges.is_empty() {
 6975                        editor.highlight_background::<SelectedTextHighlight>(
 6976                            &match_ranges,
 6977                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6978                            cx,
 6979                        )
 6980                    }
 6981                })
 6982                .log_err();
 6983        })
 6984    }
 6985
 6986    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6987        struct NewlineFold;
 6988        let type_id = std::any::TypeId::of::<NewlineFold>();
 6989        if !self.mode.is_single_line() {
 6990            return;
 6991        }
 6992        let snapshot = self.snapshot(window, cx);
 6993        if snapshot.buffer_snapshot.max_point().row == 0 {
 6994            return;
 6995        }
 6996        let task = cx.background_spawn(async move {
 6997            let new_newlines = snapshot
 6998                .buffer_chars_at(0)
 6999                .filter_map(|(c, i)| {
 7000                    if c == '\n' {
 7001                        Some(
 7002                            snapshot.buffer_snapshot.anchor_after(i)
 7003                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7004                        )
 7005                    } else {
 7006                        None
 7007                    }
 7008                })
 7009                .collect::<Vec<_>>();
 7010            let existing_newlines = snapshot
 7011                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7012                .filter_map(|fold| {
 7013                    if fold.placeholder.type_tag == Some(type_id) {
 7014                        Some(fold.range.start..fold.range.end)
 7015                    } else {
 7016                        None
 7017                    }
 7018                })
 7019                .collect::<Vec<_>>();
 7020
 7021            (new_newlines, existing_newlines)
 7022        });
 7023        self.folding_newlines = cx.spawn(async move |this, cx| {
 7024            let (new_newlines, existing_newlines) = task.await;
 7025            if new_newlines == existing_newlines {
 7026                return;
 7027            }
 7028            let placeholder = FoldPlaceholder {
 7029                render: Arc::new(move |_, _, cx| {
 7030                    div()
 7031                        .bg(cx.theme().status().hint_background)
 7032                        .border_b_1()
 7033                        .size_full()
 7034                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7035                        .border_color(cx.theme().status().hint)
 7036                        .child("\\n")
 7037                        .into_any()
 7038                }),
 7039                constrain_width: false,
 7040                merge_adjacent: false,
 7041                type_tag: Some(type_id),
 7042            };
 7043            let creases = new_newlines
 7044                .into_iter()
 7045                .map(|range| Crease::simple(range, placeholder.clone()))
 7046                .collect();
 7047            this.update(cx, |this, cx| {
 7048                this.display_map.update(cx, |display_map, cx| {
 7049                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7050                    display_map.fold(creases, cx);
 7051                });
 7052            })
 7053            .ok();
 7054        });
 7055    }
 7056
 7057    fn refresh_selected_text_highlights(
 7058        &mut self,
 7059        on_buffer_edit: bool,
 7060        window: &mut Window,
 7061        cx: &mut Context<Editor>,
 7062    ) {
 7063        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7064        else {
 7065            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7066            self.quick_selection_highlight_task.take();
 7067            self.debounced_selection_highlight_task.take();
 7068            return;
 7069        };
 7070        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7071        if on_buffer_edit
 7072            || self
 7073                .quick_selection_highlight_task
 7074                .as_ref()
 7075                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7076        {
 7077            let multi_buffer_visible_start = self
 7078                .scroll_manager
 7079                .anchor()
 7080                .anchor
 7081                .to_point(&multi_buffer_snapshot);
 7082            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7083                multi_buffer_visible_start
 7084                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7085                Bias::Left,
 7086            );
 7087            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7088            self.quick_selection_highlight_task = Some((
 7089                query_range.clone(),
 7090                self.update_selection_occurrence_highlights(
 7091                    query_text.clone(),
 7092                    query_range.clone(),
 7093                    multi_buffer_visible_range,
 7094                    false,
 7095                    window,
 7096                    cx,
 7097                ),
 7098            ));
 7099        }
 7100        if on_buffer_edit
 7101            || self
 7102                .debounced_selection_highlight_task
 7103                .as_ref()
 7104                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7105        {
 7106            let multi_buffer_start = multi_buffer_snapshot
 7107                .anchor_before(0)
 7108                .to_point(&multi_buffer_snapshot);
 7109            let multi_buffer_end = multi_buffer_snapshot
 7110                .anchor_after(multi_buffer_snapshot.len())
 7111                .to_point(&multi_buffer_snapshot);
 7112            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7113            self.debounced_selection_highlight_task = Some((
 7114                query_range.clone(),
 7115                self.update_selection_occurrence_highlights(
 7116                    query_text,
 7117                    query_range,
 7118                    multi_buffer_full_range,
 7119                    true,
 7120                    window,
 7121                    cx,
 7122                ),
 7123            ));
 7124        }
 7125    }
 7126
 7127    pub fn refresh_edit_prediction(
 7128        &mut self,
 7129        debounce: bool,
 7130        user_requested: bool,
 7131        window: &mut Window,
 7132        cx: &mut Context<Self>,
 7133    ) -> Option<()> {
 7134        if DisableAiSettings::get_global(cx).disable_ai {
 7135            return None;
 7136        }
 7137
 7138        let provider = self.edit_prediction_provider()?;
 7139        let cursor = self.selections.newest_anchor().head();
 7140        let (buffer, cursor_buffer_position) =
 7141            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7142
 7143        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7144            self.discard_edit_prediction(false, cx);
 7145            return None;
 7146        }
 7147
 7148        if !user_requested
 7149            && (!self.should_show_edit_predictions()
 7150                || !self.is_focused(window)
 7151                || buffer.read(cx).is_empty())
 7152        {
 7153            self.discard_edit_prediction(false, cx);
 7154            return None;
 7155        }
 7156
 7157        self.update_visible_edit_prediction(window, cx);
 7158        provider.refresh(
 7159            self.project.clone(),
 7160            buffer,
 7161            cursor_buffer_position,
 7162            debounce,
 7163            cx,
 7164        );
 7165        Some(())
 7166    }
 7167
 7168    fn show_edit_predictions_in_menu(&self) -> bool {
 7169        match self.edit_prediction_settings {
 7170            EditPredictionSettings::Disabled => false,
 7171            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7172        }
 7173    }
 7174
 7175    pub fn edit_predictions_enabled(&self) -> bool {
 7176        match self.edit_prediction_settings {
 7177            EditPredictionSettings::Disabled => false,
 7178            EditPredictionSettings::Enabled { .. } => true,
 7179        }
 7180    }
 7181
 7182    fn edit_prediction_requires_modifier(&self) -> bool {
 7183        match self.edit_prediction_settings {
 7184            EditPredictionSettings::Disabled => false,
 7185            EditPredictionSettings::Enabled {
 7186                preview_requires_modifier,
 7187                ..
 7188            } => preview_requires_modifier,
 7189        }
 7190    }
 7191
 7192    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7193        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7194            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7195            self.discard_edit_prediction(false, cx);
 7196        } else {
 7197            let selection = self.selections.newest_anchor();
 7198            let cursor = selection.head();
 7199
 7200            if let Some((buffer, cursor_buffer_position)) =
 7201                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7202            {
 7203                self.edit_prediction_settings =
 7204                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7205            }
 7206        }
 7207    }
 7208
 7209    fn edit_prediction_settings_at_position(
 7210        &self,
 7211        buffer: &Entity<Buffer>,
 7212        buffer_position: language::Anchor,
 7213        cx: &App,
 7214    ) -> EditPredictionSettings {
 7215        if !self.mode.is_full()
 7216            || !self.show_edit_predictions_override.unwrap_or(true)
 7217            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7218        {
 7219            return EditPredictionSettings::Disabled;
 7220        }
 7221
 7222        let buffer = buffer.read(cx);
 7223
 7224        let file = buffer.file();
 7225
 7226        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7227            return EditPredictionSettings::Disabled;
 7228        };
 7229
 7230        let by_provider = matches!(
 7231            self.menu_edit_predictions_policy,
 7232            MenuEditPredictionsPolicy::ByProvider
 7233        );
 7234
 7235        let show_in_menu = by_provider
 7236            && self
 7237                .edit_prediction_provider
 7238                .as_ref()
 7239                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7240
 7241        let preview_requires_modifier =
 7242            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7243
 7244        EditPredictionSettings::Enabled {
 7245            show_in_menu,
 7246            preview_requires_modifier,
 7247        }
 7248    }
 7249
 7250    fn should_show_edit_predictions(&self) -> bool {
 7251        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7252    }
 7253
 7254    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7255        matches!(
 7256            self.edit_prediction_preview,
 7257            EditPredictionPreview::Active { .. }
 7258        )
 7259    }
 7260
 7261    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7262        let cursor = self.selections.newest_anchor().head();
 7263        if let Some((buffer, cursor_position)) =
 7264            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7265        {
 7266            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7267        } else {
 7268            false
 7269        }
 7270    }
 7271
 7272    pub fn supports_minimap(&self, cx: &App) -> bool {
 7273        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7274    }
 7275
 7276    fn edit_predictions_enabled_in_buffer(
 7277        &self,
 7278        buffer: &Entity<Buffer>,
 7279        buffer_position: language::Anchor,
 7280        cx: &App,
 7281    ) -> bool {
 7282        maybe!({
 7283            if self.read_only(cx) {
 7284                return Some(false);
 7285            }
 7286            let provider = self.edit_prediction_provider()?;
 7287            if !provider.is_enabled(buffer, buffer_position, cx) {
 7288                return Some(false);
 7289            }
 7290            let buffer = buffer.read(cx);
 7291            let Some(file) = buffer.file() else {
 7292                return Some(true);
 7293            };
 7294            let settings = all_language_settings(Some(file), cx);
 7295            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7296        })
 7297        .unwrap_or(false)
 7298    }
 7299
 7300    fn cycle_edit_prediction(
 7301        &mut self,
 7302        direction: Direction,
 7303        window: &mut Window,
 7304        cx: &mut Context<Self>,
 7305    ) -> Option<()> {
 7306        let provider = self.edit_prediction_provider()?;
 7307        let cursor = self.selections.newest_anchor().head();
 7308        let (buffer, cursor_buffer_position) =
 7309            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7310        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7311            return None;
 7312        }
 7313
 7314        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7315        self.update_visible_edit_prediction(window, cx);
 7316
 7317        Some(())
 7318    }
 7319
 7320    pub fn show_edit_prediction(
 7321        &mut self,
 7322        _: &ShowEditPrediction,
 7323        window: &mut Window,
 7324        cx: &mut Context<Self>,
 7325    ) {
 7326        if !self.has_active_edit_prediction() {
 7327            self.refresh_edit_prediction(false, true, window, cx);
 7328            return;
 7329        }
 7330
 7331        self.update_visible_edit_prediction(window, cx);
 7332    }
 7333
 7334    pub fn display_cursor_names(
 7335        &mut self,
 7336        _: &DisplayCursorNames,
 7337        window: &mut Window,
 7338        cx: &mut Context<Self>,
 7339    ) {
 7340        self.show_cursor_names(window, cx);
 7341    }
 7342
 7343    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7344        self.show_cursor_names = true;
 7345        cx.notify();
 7346        cx.spawn_in(window, async move |this, cx| {
 7347            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7348            this.update(cx, |this, cx| {
 7349                this.show_cursor_names = false;
 7350                cx.notify()
 7351            })
 7352            .ok()
 7353        })
 7354        .detach();
 7355    }
 7356
 7357    pub fn next_edit_prediction(
 7358        &mut self,
 7359        _: &NextEditPrediction,
 7360        window: &mut Window,
 7361        cx: &mut Context<Self>,
 7362    ) {
 7363        if self.has_active_edit_prediction() {
 7364            self.cycle_edit_prediction(Direction::Next, window, cx);
 7365        } else {
 7366            let is_copilot_disabled = self
 7367                .refresh_edit_prediction(false, true, window, cx)
 7368                .is_none();
 7369            if is_copilot_disabled {
 7370                cx.propagate();
 7371            }
 7372        }
 7373    }
 7374
 7375    pub fn previous_edit_prediction(
 7376        &mut self,
 7377        _: &PreviousEditPrediction,
 7378        window: &mut Window,
 7379        cx: &mut Context<Self>,
 7380    ) {
 7381        if self.has_active_edit_prediction() {
 7382            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7383        } else {
 7384            let is_copilot_disabled = self
 7385                .refresh_edit_prediction(false, true, window, cx)
 7386                .is_none();
 7387            if is_copilot_disabled {
 7388                cx.propagate();
 7389            }
 7390        }
 7391    }
 7392
 7393    pub fn accept_edit_prediction(
 7394        &mut self,
 7395        _: &AcceptEditPrediction,
 7396        window: &mut Window,
 7397        cx: &mut Context<Self>,
 7398    ) {
 7399        if self.show_edit_predictions_in_menu() {
 7400            self.hide_context_menu(window, cx);
 7401        }
 7402
 7403        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7404            return;
 7405        };
 7406
 7407        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7408
 7409        match &active_edit_prediction.completion {
 7410            EditPrediction::Move { target, .. } => {
 7411                let target = *target;
 7412
 7413                if let Some(position_map) = &self.last_position_map {
 7414                    if position_map
 7415                        .visible_row_range
 7416                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7417                        || !self.edit_prediction_requires_modifier()
 7418                    {
 7419                        self.unfold_ranges(&[target..target], true, false, cx);
 7420                        // Note that this is also done in vim's handler of the Tab action.
 7421                        self.change_selections(
 7422                            SelectionEffects::scroll(Autoscroll::newest()),
 7423                            window,
 7424                            cx,
 7425                            |selections| {
 7426                                selections.select_anchor_ranges([target..target]);
 7427                            },
 7428                        );
 7429                        self.clear_row_highlights::<EditPredictionPreview>();
 7430
 7431                        self.edit_prediction_preview
 7432                            .set_previous_scroll_position(None);
 7433                    } else {
 7434                        self.edit_prediction_preview
 7435                            .set_previous_scroll_position(Some(
 7436                                position_map.snapshot.scroll_anchor,
 7437                            ));
 7438
 7439                        self.highlight_rows::<EditPredictionPreview>(
 7440                            target..target,
 7441                            cx.theme().colors().editor_highlighted_line_background,
 7442                            RowHighlightOptions {
 7443                                autoscroll: true,
 7444                                ..Default::default()
 7445                            },
 7446                            cx,
 7447                        );
 7448                        self.request_autoscroll(Autoscroll::fit(), cx);
 7449                    }
 7450                }
 7451            }
 7452            EditPrediction::Edit { edits, .. } => {
 7453                if let Some(provider) = self.edit_prediction_provider() {
 7454                    provider.accept(cx);
 7455                }
 7456
 7457                // Store the transaction ID and selections before applying the edit
 7458                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7459
 7460                let snapshot = self.buffer.read(cx).snapshot(cx);
 7461                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7462
 7463                self.buffer.update(cx, |buffer, cx| {
 7464                    buffer.edit(edits.iter().cloned(), None, cx)
 7465                });
 7466
 7467                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7468                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7469                });
 7470
 7471                let selections = self.selections.disjoint_anchors();
 7472                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7473                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7474                    if has_new_transaction {
 7475                        self.selection_history
 7476                            .insert_transaction(transaction_id_now, selections);
 7477                    }
 7478                }
 7479
 7480                self.update_visible_edit_prediction(window, cx);
 7481                if self.active_edit_prediction.is_none() {
 7482                    self.refresh_edit_prediction(true, true, window, cx);
 7483                }
 7484
 7485                cx.notify();
 7486            }
 7487        }
 7488
 7489        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7490    }
 7491
 7492    pub fn accept_partial_edit_prediction(
 7493        &mut self,
 7494        _: &AcceptPartialEditPrediction,
 7495        window: &mut Window,
 7496        cx: &mut Context<Self>,
 7497    ) {
 7498        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7499            return;
 7500        };
 7501        if self.selections.count() != 1 {
 7502            return;
 7503        }
 7504
 7505        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7506
 7507        match &active_edit_prediction.completion {
 7508            EditPrediction::Move { target, .. } => {
 7509                let target = *target;
 7510                self.change_selections(
 7511                    SelectionEffects::scroll(Autoscroll::newest()),
 7512                    window,
 7513                    cx,
 7514                    |selections| {
 7515                        selections.select_anchor_ranges([target..target]);
 7516                    },
 7517                );
 7518            }
 7519            EditPrediction::Edit { edits, .. } => {
 7520                // Find an insertion that starts at the cursor position.
 7521                let snapshot = self.buffer.read(cx).snapshot(cx);
 7522                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7523                let insertion = edits.iter().find_map(|(range, text)| {
 7524                    let range = range.to_offset(&snapshot);
 7525                    if range.is_empty() && range.start == cursor_offset {
 7526                        Some(text)
 7527                    } else {
 7528                        None
 7529                    }
 7530                });
 7531
 7532                if let Some(text) = insertion {
 7533                    let mut partial_completion = text
 7534                        .chars()
 7535                        .by_ref()
 7536                        .take_while(|c| c.is_alphabetic())
 7537                        .collect::<String>();
 7538                    if partial_completion.is_empty() {
 7539                        partial_completion = text
 7540                            .chars()
 7541                            .by_ref()
 7542                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7543                            .collect::<String>();
 7544                    }
 7545
 7546                    cx.emit(EditorEvent::InputHandled {
 7547                        utf16_range_to_replace: None,
 7548                        text: partial_completion.clone().into(),
 7549                    });
 7550
 7551                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7552
 7553                    self.refresh_edit_prediction(true, true, window, cx);
 7554                    cx.notify();
 7555                } else {
 7556                    self.accept_edit_prediction(&Default::default(), window, cx);
 7557                }
 7558            }
 7559        }
 7560    }
 7561
 7562    fn discard_edit_prediction(
 7563        &mut self,
 7564        should_report_edit_prediction_event: bool,
 7565        cx: &mut Context<Self>,
 7566    ) -> bool {
 7567        if should_report_edit_prediction_event {
 7568            let completion_id = self
 7569                .active_edit_prediction
 7570                .as_ref()
 7571                .and_then(|active_completion| active_completion.completion_id.clone());
 7572
 7573            self.report_edit_prediction_event(completion_id, false, cx);
 7574        }
 7575
 7576        if let Some(provider) = self.edit_prediction_provider() {
 7577            provider.discard(cx);
 7578        }
 7579
 7580        self.take_active_edit_prediction(cx)
 7581    }
 7582
 7583    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7584        let Some(provider) = self.edit_prediction_provider() else {
 7585            return;
 7586        };
 7587
 7588        let Some((_, buffer, _)) = self
 7589            .buffer
 7590            .read(cx)
 7591            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7592        else {
 7593            return;
 7594        };
 7595
 7596        let extension = buffer
 7597            .read(cx)
 7598            .file()
 7599            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7600
 7601        let event_type = match accepted {
 7602            true => "Edit Prediction Accepted",
 7603            false => "Edit Prediction Discarded",
 7604        };
 7605        telemetry::event!(
 7606            event_type,
 7607            provider = provider.name(),
 7608            prediction_id = id,
 7609            suggestion_accepted = accepted,
 7610            file_extension = extension,
 7611        );
 7612    }
 7613
 7614    pub fn has_active_edit_prediction(&self) -> bool {
 7615        self.active_edit_prediction.is_some()
 7616    }
 7617
 7618    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7619        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7620            return false;
 7621        };
 7622
 7623        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7624        self.clear_highlights::<EditPredictionHighlight>(cx);
 7625        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7626        true
 7627    }
 7628
 7629    /// Returns true when we're displaying the edit prediction popover below the cursor
 7630    /// like we are not previewing and the LSP autocomplete menu is visible
 7631    /// or we are in `when_holding_modifier` mode.
 7632    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7633        if self.edit_prediction_preview_is_active()
 7634            || !self.show_edit_predictions_in_menu()
 7635            || !self.edit_predictions_enabled()
 7636        {
 7637            return false;
 7638        }
 7639
 7640        if self.has_visible_completions_menu() {
 7641            return true;
 7642        }
 7643
 7644        has_completion && self.edit_prediction_requires_modifier()
 7645    }
 7646
 7647    fn handle_modifiers_changed(
 7648        &mut self,
 7649        modifiers: Modifiers,
 7650        position_map: &PositionMap,
 7651        window: &mut Window,
 7652        cx: &mut Context<Self>,
 7653    ) {
 7654        if self.show_edit_predictions_in_menu() {
 7655            self.update_edit_prediction_preview(&modifiers, window, cx);
 7656        }
 7657
 7658        self.update_selection_mode(&modifiers, position_map, window, cx);
 7659
 7660        let mouse_position = window.mouse_position();
 7661        if !position_map.text_hitbox.is_hovered(window) {
 7662            return;
 7663        }
 7664
 7665        self.update_hovered_link(
 7666            position_map.point_for_position(mouse_position),
 7667            &position_map.snapshot,
 7668            modifiers,
 7669            window,
 7670            cx,
 7671        )
 7672    }
 7673
 7674    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7675        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7676        if invert {
 7677            match multi_cursor_setting {
 7678                MultiCursorModifier::Alt => modifiers.alt,
 7679                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7680            }
 7681        } else {
 7682            match multi_cursor_setting {
 7683                MultiCursorModifier::Alt => modifiers.secondary(),
 7684                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7685            }
 7686        }
 7687    }
 7688
 7689    fn columnar_selection_mode(
 7690        modifiers: &Modifiers,
 7691        cx: &mut Context<Self>,
 7692    ) -> Option<ColumnarMode> {
 7693        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7694            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7695                Some(ColumnarMode::FromMouse)
 7696            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7697                Some(ColumnarMode::FromSelection)
 7698            } else {
 7699                None
 7700            }
 7701        } else {
 7702            None
 7703        }
 7704    }
 7705
 7706    fn update_selection_mode(
 7707        &mut self,
 7708        modifiers: &Modifiers,
 7709        position_map: &PositionMap,
 7710        window: &mut Window,
 7711        cx: &mut Context<Self>,
 7712    ) {
 7713        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7714            return;
 7715        };
 7716        if self.selections.pending.is_none() {
 7717            return;
 7718        }
 7719
 7720        let mouse_position = window.mouse_position();
 7721        let point_for_position = position_map.point_for_position(mouse_position);
 7722        let position = point_for_position.previous_valid;
 7723
 7724        self.select(
 7725            SelectPhase::BeginColumnar {
 7726                position,
 7727                reset: false,
 7728                mode,
 7729                goal_column: point_for_position.exact_unclipped.column(),
 7730            },
 7731            window,
 7732            cx,
 7733        );
 7734    }
 7735
 7736    fn update_edit_prediction_preview(
 7737        &mut self,
 7738        modifiers: &Modifiers,
 7739        window: &mut Window,
 7740        cx: &mut Context<Self>,
 7741    ) {
 7742        let mut modifiers_held = false;
 7743        if let Some(accept_keystroke) = self
 7744            .accept_edit_prediction_keybind(false, window, cx)
 7745            .keystroke()
 7746        {
 7747            modifiers_held = modifiers_held
 7748                || (accept_keystroke.modifiers() == modifiers
 7749                    && accept_keystroke.modifiers().modified());
 7750        };
 7751        if let Some(accept_partial_keystroke) = self
 7752            .accept_edit_prediction_keybind(true, window, cx)
 7753            .keystroke()
 7754        {
 7755            modifiers_held = modifiers_held
 7756                || (accept_partial_keystroke.modifiers() == modifiers
 7757                    && accept_partial_keystroke.modifiers().modified());
 7758        }
 7759
 7760        if modifiers_held {
 7761            if matches!(
 7762                self.edit_prediction_preview,
 7763                EditPredictionPreview::Inactive { .. }
 7764            ) {
 7765                self.edit_prediction_preview = EditPredictionPreview::Active {
 7766                    previous_scroll_position: None,
 7767                    since: Instant::now(),
 7768                };
 7769
 7770                self.update_visible_edit_prediction(window, cx);
 7771                cx.notify();
 7772            }
 7773        } else if let EditPredictionPreview::Active {
 7774            previous_scroll_position,
 7775            since,
 7776        } = self.edit_prediction_preview
 7777        {
 7778            if let (Some(previous_scroll_position), Some(position_map)) =
 7779                (previous_scroll_position, self.last_position_map.as_ref())
 7780            {
 7781                self.set_scroll_position(
 7782                    previous_scroll_position
 7783                        .scroll_position(&position_map.snapshot.display_snapshot),
 7784                    window,
 7785                    cx,
 7786                );
 7787            }
 7788
 7789            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7790                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7791            };
 7792            self.clear_row_highlights::<EditPredictionPreview>();
 7793            self.update_visible_edit_prediction(window, cx);
 7794            cx.notify();
 7795        }
 7796    }
 7797
 7798    fn update_visible_edit_prediction(
 7799        &mut self,
 7800        _window: &mut Window,
 7801        cx: &mut Context<Self>,
 7802    ) -> Option<()> {
 7803        if DisableAiSettings::get_global(cx).disable_ai {
 7804            return None;
 7805        }
 7806
 7807        if self.ime_transaction.is_some() {
 7808            self.discard_edit_prediction(false, cx);
 7809            return None;
 7810        }
 7811
 7812        let selection = self.selections.newest_anchor();
 7813        let cursor = selection.head();
 7814        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7815        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7816        let excerpt_id = cursor.excerpt_id;
 7817
 7818        let show_in_menu = self.show_edit_predictions_in_menu();
 7819        let completions_menu_has_precedence = !show_in_menu
 7820            && (self.context_menu.borrow().is_some()
 7821                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7822
 7823        if completions_menu_has_precedence
 7824            || !offset_selection.is_empty()
 7825            || self
 7826                .active_edit_prediction
 7827                .as_ref()
 7828                .is_some_and(|completion| {
 7829                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7830                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7831                    !invalidation_range.contains(&offset_selection.head())
 7832                })
 7833        {
 7834            self.discard_edit_prediction(false, cx);
 7835            return None;
 7836        }
 7837
 7838        self.take_active_edit_prediction(cx);
 7839        let Some(provider) = self.edit_prediction_provider() else {
 7840            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7841            return None;
 7842        };
 7843
 7844        let (buffer, cursor_buffer_position) =
 7845            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7846
 7847        self.edit_prediction_settings =
 7848            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7849
 7850        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7851            self.discard_edit_prediction(false, cx);
 7852            return None;
 7853        };
 7854
 7855        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7856
 7857        if self.edit_prediction_indent_conflict {
 7858            let cursor_point = cursor.to_point(&multibuffer);
 7859
 7860            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7861
 7862            if let Some((_, indent)) = indents.iter().next()
 7863                && indent.len == cursor_point.column
 7864            {
 7865                self.edit_prediction_indent_conflict = false;
 7866            }
 7867        }
 7868
 7869        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7870        let edits = edit_prediction
 7871            .edits
 7872            .into_iter()
 7873            .flat_map(|(range, new_text)| {
 7874                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7875                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7876                Some((start..end, new_text))
 7877            })
 7878            .collect::<Vec<_>>();
 7879        if edits.is_empty() {
 7880            return None;
 7881        }
 7882
 7883        let first_edit_start = edits.first().unwrap().0.start;
 7884        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7885        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7886
 7887        let last_edit_end = edits.last().unwrap().0.end;
 7888        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7889        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7890
 7891        let cursor_row = cursor.to_point(&multibuffer).row;
 7892
 7893        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7894
 7895        let mut inlay_ids = Vec::new();
 7896        let invalidation_row_range;
 7897        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7898            Some(cursor_row..edit_end_row)
 7899        } else if cursor_row > edit_end_row {
 7900            Some(edit_start_row..cursor_row)
 7901        } else {
 7902            None
 7903        };
 7904        let supports_jump = self
 7905            .edit_prediction_provider
 7906            .as_ref()
 7907            .map(|provider| provider.provider.supports_jump_to_edit())
 7908            .unwrap_or(true);
 7909
 7910        let is_move = supports_jump
 7911            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7912        let completion = if is_move {
 7913            invalidation_row_range =
 7914                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7915            let target = first_edit_start;
 7916            EditPrediction::Move { target, snapshot }
 7917        } else {
 7918            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7919                && !self.edit_predictions_hidden_for_vim_mode;
 7920
 7921            if show_completions_in_buffer {
 7922                if edits
 7923                    .iter()
 7924                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7925                {
 7926                    let mut inlays = Vec::new();
 7927                    for (range, new_text) in &edits {
 7928                        let inlay = Inlay::edit_prediction(
 7929                            post_inc(&mut self.next_inlay_id),
 7930                            range.start,
 7931                            new_text.as_str(),
 7932                        );
 7933                        inlay_ids.push(inlay.id);
 7934                        inlays.push(inlay);
 7935                    }
 7936
 7937                    self.splice_inlays(&[], inlays, cx);
 7938                } else {
 7939                    let background_color = cx.theme().status().deleted_background;
 7940                    self.highlight_text::<EditPredictionHighlight>(
 7941                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7942                        HighlightStyle {
 7943                            background_color: Some(background_color),
 7944                            ..Default::default()
 7945                        },
 7946                        cx,
 7947                    );
 7948                }
 7949            }
 7950
 7951            invalidation_row_range = edit_start_row..edit_end_row;
 7952
 7953            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7954                if provider.show_tab_accept_marker() {
 7955                    EditDisplayMode::TabAccept
 7956                } else {
 7957                    EditDisplayMode::Inline
 7958                }
 7959            } else {
 7960                EditDisplayMode::DiffPopover
 7961            };
 7962
 7963            EditPrediction::Edit {
 7964                edits,
 7965                edit_preview: edit_prediction.edit_preview,
 7966                display_mode,
 7967                snapshot,
 7968            }
 7969        };
 7970
 7971        let invalidation_range = multibuffer
 7972            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7973            ..multibuffer.anchor_after(Point::new(
 7974                invalidation_row_range.end,
 7975                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7976            ));
 7977
 7978        self.stale_edit_prediction_in_menu = None;
 7979        self.active_edit_prediction = Some(EditPredictionState {
 7980            inlay_ids,
 7981            completion,
 7982            completion_id: edit_prediction.id,
 7983            invalidation_range,
 7984        });
 7985
 7986        cx.notify();
 7987
 7988        Some(())
 7989    }
 7990
 7991    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7992        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7993    }
 7994
 7995    fn clear_tasks(&mut self) {
 7996        self.tasks.clear()
 7997    }
 7998
 7999    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8000        if self.tasks.insert(key, value).is_some() {
 8001            // This case should hopefully be rare, but just in case...
 8002            log::error!(
 8003                "multiple different run targets found on a single line, only the last target will be rendered"
 8004            )
 8005        }
 8006    }
 8007
 8008    /// Get all display points of breakpoints that will be rendered within editor
 8009    ///
 8010    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8011    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8012    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8013    fn active_breakpoints(
 8014        &self,
 8015        range: Range<DisplayRow>,
 8016        window: &mut Window,
 8017        cx: &mut Context<Self>,
 8018    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8019        let mut breakpoint_display_points = HashMap::default();
 8020
 8021        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8022            return breakpoint_display_points;
 8023        };
 8024
 8025        let snapshot = self.snapshot(window, cx);
 8026
 8027        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8028        let Some(project) = self.project() else {
 8029            return breakpoint_display_points;
 8030        };
 8031
 8032        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8033            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8034
 8035        for (buffer_snapshot, range, excerpt_id) in
 8036            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8037        {
 8038            let Some(buffer) = project
 8039                .read(cx)
 8040                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8041            else {
 8042                continue;
 8043            };
 8044            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8045                &buffer,
 8046                Some(
 8047                    buffer_snapshot.anchor_before(range.start)
 8048                        ..buffer_snapshot.anchor_after(range.end),
 8049                ),
 8050                buffer_snapshot,
 8051                cx,
 8052            );
 8053            for (breakpoint, state) in breakpoints {
 8054                let multi_buffer_anchor =
 8055                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8056                let position = multi_buffer_anchor
 8057                    .to_point(multi_buffer_snapshot)
 8058                    .to_display_point(&snapshot);
 8059
 8060                breakpoint_display_points.insert(
 8061                    position.row(),
 8062                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8063                );
 8064            }
 8065        }
 8066
 8067        breakpoint_display_points
 8068    }
 8069
 8070    fn breakpoint_context_menu(
 8071        &self,
 8072        anchor: Anchor,
 8073        window: &mut Window,
 8074        cx: &mut Context<Self>,
 8075    ) -> Entity<ui::ContextMenu> {
 8076        let weak_editor = cx.weak_entity();
 8077        let focus_handle = self.focus_handle(cx);
 8078
 8079        let row = self
 8080            .buffer
 8081            .read(cx)
 8082            .snapshot(cx)
 8083            .summary_for_anchor::<Point>(&anchor)
 8084            .row;
 8085
 8086        let breakpoint = self
 8087            .breakpoint_at_row(row, window, cx)
 8088            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8089
 8090        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8091            "Edit Log Breakpoint"
 8092        } else {
 8093            "Set Log Breakpoint"
 8094        };
 8095
 8096        let condition_breakpoint_msg = if breakpoint
 8097            .as_ref()
 8098            .is_some_and(|bp| bp.1.condition.is_some())
 8099        {
 8100            "Edit Condition Breakpoint"
 8101        } else {
 8102            "Set Condition Breakpoint"
 8103        };
 8104
 8105        let hit_condition_breakpoint_msg = if breakpoint
 8106            .as_ref()
 8107            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8108        {
 8109            "Edit Hit Condition Breakpoint"
 8110        } else {
 8111            "Set Hit Condition Breakpoint"
 8112        };
 8113
 8114        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8115            "Unset Breakpoint"
 8116        } else {
 8117            "Set Breakpoint"
 8118        };
 8119
 8120        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8121
 8122        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8123            BreakpointState::Enabled => Some("Disable"),
 8124            BreakpointState::Disabled => Some("Enable"),
 8125        });
 8126
 8127        let (anchor, breakpoint) =
 8128            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8129
 8130        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8131            menu.on_blur_subscription(Subscription::new(|| {}))
 8132                .context(focus_handle)
 8133                .when(run_to_cursor, |this| {
 8134                    let weak_editor = weak_editor.clone();
 8135                    this.entry("Run to cursor", None, move |window, cx| {
 8136                        weak_editor
 8137                            .update(cx, |editor, cx| {
 8138                                editor.change_selections(
 8139                                    SelectionEffects::no_scroll(),
 8140                                    window,
 8141                                    cx,
 8142                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8143                                );
 8144                            })
 8145                            .ok();
 8146
 8147                        window.dispatch_action(Box::new(RunToCursor), cx);
 8148                    })
 8149                    .separator()
 8150                })
 8151                .when_some(toggle_state_msg, |this, msg| {
 8152                    this.entry(msg, None, {
 8153                        let weak_editor = weak_editor.clone();
 8154                        let breakpoint = breakpoint.clone();
 8155                        move |_window, cx| {
 8156                            weak_editor
 8157                                .update(cx, |this, cx| {
 8158                                    this.edit_breakpoint_at_anchor(
 8159                                        anchor,
 8160                                        breakpoint.as_ref().clone(),
 8161                                        BreakpointEditAction::InvertState,
 8162                                        cx,
 8163                                    );
 8164                                })
 8165                                .log_err();
 8166                        }
 8167                    })
 8168                })
 8169                .entry(set_breakpoint_msg, None, {
 8170                    let weak_editor = weak_editor.clone();
 8171                    let breakpoint = breakpoint.clone();
 8172                    move |_window, cx| {
 8173                        weak_editor
 8174                            .update(cx, |this, cx| {
 8175                                this.edit_breakpoint_at_anchor(
 8176                                    anchor,
 8177                                    breakpoint.as_ref().clone(),
 8178                                    BreakpointEditAction::Toggle,
 8179                                    cx,
 8180                                );
 8181                            })
 8182                            .log_err();
 8183                    }
 8184                })
 8185                .entry(log_breakpoint_msg, None, {
 8186                    let breakpoint = breakpoint.clone();
 8187                    let weak_editor = weak_editor.clone();
 8188                    move |window, cx| {
 8189                        weak_editor
 8190                            .update(cx, |this, cx| {
 8191                                this.add_edit_breakpoint_block(
 8192                                    anchor,
 8193                                    breakpoint.as_ref(),
 8194                                    BreakpointPromptEditAction::Log,
 8195                                    window,
 8196                                    cx,
 8197                                );
 8198                            })
 8199                            .log_err();
 8200                    }
 8201                })
 8202                .entry(condition_breakpoint_msg, None, {
 8203                    let breakpoint = breakpoint.clone();
 8204                    let weak_editor = weak_editor.clone();
 8205                    move |window, cx| {
 8206                        weak_editor
 8207                            .update(cx, |this, cx| {
 8208                                this.add_edit_breakpoint_block(
 8209                                    anchor,
 8210                                    breakpoint.as_ref(),
 8211                                    BreakpointPromptEditAction::Condition,
 8212                                    window,
 8213                                    cx,
 8214                                );
 8215                            })
 8216                            .log_err();
 8217                    }
 8218                })
 8219                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8220                    weak_editor
 8221                        .update(cx, |this, cx| {
 8222                            this.add_edit_breakpoint_block(
 8223                                anchor,
 8224                                breakpoint.as_ref(),
 8225                                BreakpointPromptEditAction::HitCondition,
 8226                                window,
 8227                                cx,
 8228                            );
 8229                        })
 8230                        .log_err();
 8231                })
 8232        })
 8233    }
 8234
 8235    fn render_breakpoint(
 8236        &self,
 8237        position: Anchor,
 8238        row: DisplayRow,
 8239        breakpoint: &Breakpoint,
 8240        state: Option<BreakpointSessionState>,
 8241        cx: &mut Context<Self>,
 8242    ) -> IconButton {
 8243        let is_rejected = state.is_some_and(|s| !s.verified);
 8244        // Is it a breakpoint that shows up when hovering over gutter?
 8245        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8246            (false, false),
 8247            |PhantomBreakpointIndicator {
 8248                 is_active,
 8249                 display_row,
 8250                 collides_with_existing_breakpoint,
 8251             }| {
 8252                (
 8253                    is_active && display_row == row,
 8254                    collides_with_existing_breakpoint,
 8255                )
 8256            },
 8257        );
 8258
 8259        let (color, icon) = {
 8260            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8261                (false, false) => ui::IconName::DebugBreakpoint,
 8262                (true, false) => ui::IconName::DebugLogBreakpoint,
 8263                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8264                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8265            };
 8266
 8267            let color = if is_phantom {
 8268                Color::Hint
 8269            } else if is_rejected {
 8270                Color::Disabled
 8271            } else {
 8272                Color::Debugger
 8273            };
 8274
 8275            (color, icon)
 8276        };
 8277
 8278        let breakpoint = Arc::from(breakpoint.clone());
 8279
 8280        let alt_as_text = gpui::Keystroke {
 8281            modifiers: Modifiers::secondary_key(),
 8282            ..Default::default()
 8283        };
 8284        let primary_action_text = if breakpoint.is_disabled() {
 8285            "Enable breakpoint"
 8286        } else if is_phantom && !collides_with_existing {
 8287            "Set breakpoint"
 8288        } else {
 8289            "Unset breakpoint"
 8290        };
 8291        let focus_handle = self.focus_handle.clone();
 8292
 8293        let meta = if is_rejected {
 8294            SharedString::from("No executable code is associated with this line.")
 8295        } else if collides_with_existing && !breakpoint.is_disabled() {
 8296            SharedString::from(format!(
 8297                "{alt_as_text}-click to disable,\nright-click for more options."
 8298            ))
 8299        } else {
 8300            SharedString::from("Right-click for more options.")
 8301        };
 8302        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8303            .icon_size(IconSize::XSmall)
 8304            .size(ui::ButtonSize::None)
 8305            .when(is_rejected, |this| {
 8306                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8307            })
 8308            .icon_color(color)
 8309            .style(ButtonStyle::Transparent)
 8310            .on_click(cx.listener({
 8311                move |editor, event: &ClickEvent, window, cx| {
 8312                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8313                        BreakpointEditAction::InvertState
 8314                    } else {
 8315                        BreakpointEditAction::Toggle
 8316                    };
 8317
 8318                    window.focus(&editor.focus_handle(cx));
 8319                    editor.edit_breakpoint_at_anchor(
 8320                        position,
 8321                        breakpoint.as_ref().clone(),
 8322                        edit_action,
 8323                        cx,
 8324                    );
 8325                }
 8326            }))
 8327            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8328                editor.set_breakpoint_context_menu(
 8329                    row,
 8330                    Some(position),
 8331                    event.position(),
 8332                    window,
 8333                    cx,
 8334                );
 8335            }))
 8336            .tooltip(move |window, cx| {
 8337                Tooltip::with_meta_in(
 8338                    primary_action_text,
 8339                    Some(&ToggleBreakpoint),
 8340                    meta.clone(),
 8341                    &focus_handle,
 8342                    window,
 8343                    cx,
 8344                )
 8345            })
 8346    }
 8347
 8348    fn build_tasks_context(
 8349        project: &Entity<Project>,
 8350        buffer: &Entity<Buffer>,
 8351        buffer_row: u32,
 8352        tasks: &Arc<RunnableTasks>,
 8353        cx: &mut Context<Self>,
 8354    ) -> Task<Option<task::TaskContext>> {
 8355        let position = Point::new(buffer_row, tasks.column);
 8356        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8357        let location = Location {
 8358            buffer: buffer.clone(),
 8359            range: range_start..range_start,
 8360        };
 8361        // Fill in the environmental variables from the tree-sitter captures
 8362        let mut captured_task_variables = TaskVariables::default();
 8363        for (capture_name, value) in tasks.extra_variables.clone() {
 8364            captured_task_variables.insert(
 8365                task::VariableName::Custom(capture_name.into()),
 8366                value.clone(),
 8367            );
 8368        }
 8369        project.update(cx, |project, cx| {
 8370            project.task_store().update(cx, |task_store, cx| {
 8371                task_store.task_context_for_location(captured_task_variables, location, cx)
 8372            })
 8373        })
 8374    }
 8375
 8376    pub fn spawn_nearest_task(
 8377        &mut self,
 8378        action: &SpawnNearestTask,
 8379        window: &mut Window,
 8380        cx: &mut Context<Self>,
 8381    ) {
 8382        let Some((workspace, _)) = self.workspace.clone() else {
 8383            return;
 8384        };
 8385        let Some(project) = self.project.clone() else {
 8386            return;
 8387        };
 8388
 8389        // Try to find a closest, enclosing node using tree-sitter that has a task
 8390        let Some((buffer, buffer_row, tasks)) = self
 8391            .find_enclosing_node_task(cx)
 8392            // Or find the task that's closest in row-distance.
 8393            .or_else(|| self.find_closest_task(cx))
 8394        else {
 8395            return;
 8396        };
 8397
 8398        let reveal_strategy = action.reveal;
 8399        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8400        cx.spawn_in(window, async move |_, cx| {
 8401            let context = task_context.await?;
 8402            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8403
 8404            let resolved = &mut resolved_task.resolved;
 8405            resolved.reveal = reveal_strategy;
 8406
 8407            workspace
 8408                .update_in(cx, |workspace, window, cx| {
 8409                    workspace.schedule_resolved_task(
 8410                        task_source_kind,
 8411                        resolved_task,
 8412                        false,
 8413                        window,
 8414                        cx,
 8415                    );
 8416                })
 8417                .ok()
 8418        })
 8419        .detach();
 8420    }
 8421
 8422    fn find_closest_task(
 8423        &mut self,
 8424        cx: &mut Context<Self>,
 8425    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8426        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8427
 8428        let ((buffer_id, row), tasks) = self
 8429            .tasks
 8430            .iter()
 8431            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8432
 8433        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8434        let tasks = Arc::new(tasks.to_owned());
 8435        Some((buffer, *row, tasks))
 8436    }
 8437
 8438    fn find_enclosing_node_task(
 8439        &mut self,
 8440        cx: &mut Context<Self>,
 8441    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8442        let snapshot = self.buffer.read(cx).snapshot(cx);
 8443        let offset = self.selections.newest::<usize>(cx).head();
 8444        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8445        let buffer_id = excerpt.buffer().remote_id();
 8446
 8447        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8448        let mut cursor = layer.node().walk();
 8449
 8450        while cursor.goto_first_child_for_byte(offset).is_some() {
 8451            if cursor.node().end_byte() == offset {
 8452                cursor.goto_next_sibling();
 8453            }
 8454        }
 8455
 8456        // Ascend to the smallest ancestor that contains the range and has a task.
 8457        loop {
 8458            let node = cursor.node();
 8459            let node_range = node.byte_range();
 8460            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8461
 8462            // Check if this node contains our offset
 8463            if node_range.start <= offset && node_range.end >= offset {
 8464                // If it contains offset, check for task
 8465                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8466                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8467                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8468                }
 8469            }
 8470
 8471            if !cursor.goto_parent() {
 8472                break;
 8473            }
 8474        }
 8475        None
 8476    }
 8477
 8478    fn render_run_indicator(
 8479        &self,
 8480        _style: &EditorStyle,
 8481        is_active: bool,
 8482        row: DisplayRow,
 8483        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8484        cx: &mut Context<Self>,
 8485    ) -> IconButton {
 8486        let color = Color::Muted;
 8487        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8488
 8489        IconButton::new(
 8490            ("run_indicator", row.0 as usize),
 8491            ui::IconName::PlayOutlined,
 8492        )
 8493        .shape(ui::IconButtonShape::Square)
 8494        .icon_size(IconSize::XSmall)
 8495        .icon_color(color)
 8496        .toggle_state(is_active)
 8497        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8498            let quick_launch = match e {
 8499                ClickEvent::Keyboard(_) => true,
 8500                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8501            };
 8502
 8503            window.focus(&editor.focus_handle(cx));
 8504            editor.toggle_code_actions(
 8505                &ToggleCodeActions {
 8506                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8507                    quick_launch,
 8508                },
 8509                window,
 8510                cx,
 8511            );
 8512        }))
 8513        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8514            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8515        }))
 8516    }
 8517
 8518    pub fn context_menu_visible(&self) -> bool {
 8519        !self.edit_prediction_preview_is_active()
 8520            && self
 8521                .context_menu
 8522                .borrow()
 8523                .as_ref()
 8524                .is_some_and(|menu| menu.visible())
 8525    }
 8526
 8527    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8528        self.context_menu
 8529            .borrow()
 8530            .as_ref()
 8531            .map(|menu| menu.origin())
 8532    }
 8533
 8534    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8535        self.context_menu_options = Some(options);
 8536    }
 8537
 8538    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8539    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8540
 8541    fn render_edit_prediction_popover(
 8542        &mut self,
 8543        text_bounds: &Bounds<Pixels>,
 8544        content_origin: gpui::Point<Pixels>,
 8545        right_margin: Pixels,
 8546        editor_snapshot: &EditorSnapshot,
 8547        visible_row_range: Range<DisplayRow>,
 8548        scroll_top: f32,
 8549        scroll_bottom: f32,
 8550        line_layouts: &[LineWithInvisibles],
 8551        line_height: Pixels,
 8552        scroll_pixel_position: gpui::Point<Pixels>,
 8553        newest_selection_head: Option<DisplayPoint>,
 8554        editor_width: Pixels,
 8555        style: &EditorStyle,
 8556        window: &mut Window,
 8557        cx: &mut App,
 8558    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8559        if self.mode().is_minimap() {
 8560            return None;
 8561        }
 8562        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8563
 8564        if self.edit_prediction_visible_in_cursor_popover(true) {
 8565            return None;
 8566        }
 8567
 8568        match &active_edit_prediction.completion {
 8569            EditPrediction::Move { target, .. } => {
 8570                let target_display_point = target.to_display_point(editor_snapshot);
 8571
 8572                if self.edit_prediction_requires_modifier() {
 8573                    if !self.edit_prediction_preview_is_active() {
 8574                        return None;
 8575                    }
 8576
 8577                    self.render_edit_prediction_modifier_jump_popover(
 8578                        text_bounds,
 8579                        content_origin,
 8580                        visible_row_range,
 8581                        line_layouts,
 8582                        line_height,
 8583                        scroll_pixel_position,
 8584                        newest_selection_head,
 8585                        target_display_point,
 8586                        window,
 8587                        cx,
 8588                    )
 8589                } else {
 8590                    self.render_edit_prediction_eager_jump_popover(
 8591                        text_bounds,
 8592                        content_origin,
 8593                        editor_snapshot,
 8594                        visible_row_range,
 8595                        scroll_top,
 8596                        scroll_bottom,
 8597                        line_height,
 8598                        scroll_pixel_position,
 8599                        target_display_point,
 8600                        editor_width,
 8601                        window,
 8602                        cx,
 8603                    )
 8604                }
 8605            }
 8606            EditPrediction::Edit {
 8607                display_mode: EditDisplayMode::Inline,
 8608                ..
 8609            } => None,
 8610            EditPrediction::Edit {
 8611                display_mode: EditDisplayMode::TabAccept,
 8612                edits,
 8613                ..
 8614            } => {
 8615                let range = &edits.first()?.0;
 8616                let target_display_point = range.end.to_display_point(editor_snapshot);
 8617
 8618                self.render_edit_prediction_end_of_line_popover(
 8619                    "Accept",
 8620                    editor_snapshot,
 8621                    visible_row_range,
 8622                    target_display_point,
 8623                    line_height,
 8624                    scroll_pixel_position,
 8625                    content_origin,
 8626                    editor_width,
 8627                    window,
 8628                    cx,
 8629                )
 8630            }
 8631            EditPrediction::Edit {
 8632                edits,
 8633                edit_preview,
 8634                display_mode: EditDisplayMode::DiffPopover,
 8635                snapshot,
 8636            } => self.render_edit_prediction_diff_popover(
 8637                text_bounds,
 8638                content_origin,
 8639                right_margin,
 8640                editor_snapshot,
 8641                visible_row_range,
 8642                line_layouts,
 8643                line_height,
 8644                scroll_pixel_position,
 8645                newest_selection_head,
 8646                editor_width,
 8647                style,
 8648                edits,
 8649                edit_preview,
 8650                snapshot,
 8651                window,
 8652                cx,
 8653            ),
 8654        }
 8655    }
 8656
 8657    fn render_edit_prediction_modifier_jump_popover(
 8658        &mut self,
 8659        text_bounds: &Bounds<Pixels>,
 8660        content_origin: gpui::Point<Pixels>,
 8661        visible_row_range: Range<DisplayRow>,
 8662        line_layouts: &[LineWithInvisibles],
 8663        line_height: Pixels,
 8664        scroll_pixel_position: gpui::Point<Pixels>,
 8665        newest_selection_head: Option<DisplayPoint>,
 8666        target_display_point: DisplayPoint,
 8667        window: &mut Window,
 8668        cx: &mut App,
 8669    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8670        let scrolled_content_origin =
 8671            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8672
 8673        const SCROLL_PADDING_Y: Pixels = px(12.);
 8674
 8675        if target_display_point.row() < visible_row_range.start {
 8676            return self.render_edit_prediction_scroll_popover(
 8677                |_| SCROLL_PADDING_Y,
 8678                IconName::ArrowUp,
 8679                visible_row_range,
 8680                line_layouts,
 8681                newest_selection_head,
 8682                scrolled_content_origin,
 8683                window,
 8684                cx,
 8685            );
 8686        } else if target_display_point.row() >= visible_row_range.end {
 8687            return self.render_edit_prediction_scroll_popover(
 8688                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8689                IconName::ArrowDown,
 8690                visible_row_range,
 8691                line_layouts,
 8692                newest_selection_head,
 8693                scrolled_content_origin,
 8694                window,
 8695                cx,
 8696            );
 8697        }
 8698
 8699        const POLE_WIDTH: Pixels = px(2.);
 8700
 8701        let line_layout =
 8702            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8703        let target_column = target_display_point.column() as usize;
 8704
 8705        let target_x = line_layout.x_for_index(target_column);
 8706        let target_y =
 8707            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8708
 8709        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8710
 8711        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8712        border_color.l += 0.001;
 8713
 8714        let mut element = v_flex()
 8715            .items_end()
 8716            .when(flag_on_right, |el| el.items_start())
 8717            .child(if flag_on_right {
 8718                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8719                    .rounded_bl(px(0.))
 8720                    .rounded_tl(px(0.))
 8721                    .border_l_2()
 8722                    .border_color(border_color)
 8723            } else {
 8724                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8725                    .rounded_br(px(0.))
 8726                    .rounded_tr(px(0.))
 8727                    .border_r_2()
 8728                    .border_color(border_color)
 8729            })
 8730            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8731            .into_any();
 8732
 8733        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8734
 8735        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8736            - point(
 8737                if flag_on_right {
 8738                    POLE_WIDTH
 8739                } else {
 8740                    size.width - POLE_WIDTH
 8741                },
 8742                size.height - line_height,
 8743            );
 8744
 8745        origin.x = origin.x.max(content_origin.x);
 8746
 8747        element.prepaint_at(origin, window, cx);
 8748
 8749        Some((element, origin))
 8750    }
 8751
 8752    fn render_edit_prediction_scroll_popover(
 8753        &mut self,
 8754        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8755        scroll_icon: IconName,
 8756        visible_row_range: Range<DisplayRow>,
 8757        line_layouts: &[LineWithInvisibles],
 8758        newest_selection_head: Option<DisplayPoint>,
 8759        scrolled_content_origin: gpui::Point<Pixels>,
 8760        window: &mut Window,
 8761        cx: &mut App,
 8762    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8763        let mut element = self
 8764            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8765            .into_any();
 8766
 8767        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8768
 8769        let cursor = newest_selection_head?;
 8770        let cursor_row_layout =
 8771            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8772        let cursor_column = cursor.column() as usize;
 8773
 8774        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8775
 8776        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8777
 8778        element.prepaint_at(origin, window, cx);
 8779        Some((element, origin))
 8780    }
 8781
 8782    fn render_edit_prediction_eager_jump_popover(
 8783        &mut self,
 8784        text_bounds: &Bounds<Pixels>,
 8785        content_origin: gpui::Point<Pixels>,
 8786        editor_snapshot: &EditorSnapshot,
 8787        visible_row_range: Range<DisplayRow>,
 8788        scroll_top: f32,
 8789        scroll_bottom: f32,
 8790        line_height: Pixels,
 8791        scroll_pixel_position: gpui::Point<Pixels>,
 8792        target_display_point: DisplayPoint,
 8793        editor_width: Pixels,
 8794        window: &mut Window,
 8795        cx: &mut App,
 8796    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8797        if target_display_point.row().as_f32() < scroll_top {
 8798            let mut element = self
 8799                .render_edit_prediction_line_popover(
 8800                    "Jump to Edit",
 8801                    Some(IconName::ArrowUp),
 8802                    window,
 8803                    cx,
 8804                )?
 8805                .into_any();
 8806
 8807            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8808            let offset = point(
 8809                (text_bounds.size.width - size.width) / 2.,
 8810                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8811            );
 8812
 8813            let origin = text_bounds.origin + offset;
 8814            element.prepaint_at(origin, window, cx);
 8815            Some((element, origin))
 8816        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8817            let mut element = self
 8818                .render_edit_prediction_line_popover(
 8819                    "Jump to Edit",
 8820                    Some(IconName::ArrowDown),
 8821                    window,
 8822                    cx,
 8823                )?
 8824                .into_any();
 8825
 8826            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8827            let offset = point(
 8828                (text_bounds.size.width - size.width) / 2.,
 8829                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8830            );
 8831
 8832            let origin = text_bounds.origin + offset;
 8833            element.prepaint_at(origin, window, cx);
 8834            Some((element, origin))
 8835        } else {
 8836            self.render_edit_prediction_end_of_line_popover(
 8837                "Jump to Edit",
 8838                editor_snapshot,
 8839                visible_row_range,
 8840                target_display_point,
 8841                line_height,
 8842                scroll_pixel_position,
 8843                content_origin,
 8844                editor_width,
 8845                window,
 8846                cx,
 8847            )
 8848        }
 8849    }
 8850
 8851    fn render_edit_prediction_end_of_line_popover(
 8852        self: &mut Editor,
 8853        label: &'static str,
 8854        editor_snapshot: &EditorSnapshot,
 8855        visible_row_range: Range<DisplayRow>,
 8856        target_display_point: DisplayPoint,
 8857        line_height: Pixels,
 8858        scroll_pixel_position: gpui::Point<Pixels>,
 8859        content_origin: gpui::Point<Pixels>,
 8860        editor_width: Pixels,
 8861        window: &mut Window,
 8862        cx: &mut App,
 8863    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8864        let target_line_end = DisplayPoint::new(
 8865            target_display_point.row(),
 8866            editor_snapshot.line_len(target_display_point.row()),
 8867        );
 8868
 8869        let mut element = self
 8870            .render_edit_prediction_line_popover(label, None, window, cx)?
 8871            .into_any();
 8872
 8873        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8874
 8875        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8876
 8877        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8878        let mut origin = start_point
 8879            + line_origin
 8880            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8881        origin.x = origin.x.max(content_origin.x);
 8882
 8883        let max_x = content_origin.x + editor_width - size.width;
 8884
 8885        if origin.x > max_x {
 8886            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8887
 8888            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8889                origin.y += offset;
 8890                IconName::ArrowUp
 8891            } else {
 8892                origin.y -= offset;
 8893                IconName::ArrowDown
 8894            };
 8895
 8896            element = self
 8897                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8898                .into_any();
 8899
 8900            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8901
 8902            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8903        }
 8904
 8905        element.prepaint_at(origin, window, cx);
 8906        Some((element, origin))
 8907    }
 8908
 8909    fn render_edit_prediction_diff_popover(
 8910        self: &Editor,
 8911        text_bounds: &Bounds<Pixels>,
 8912        content_origin: gpui::Point<Pixels>,
 8913        right_margin: Pixels,
 8914        editor_snapshot: &EditorSnapshot,
 8915        visible_row_range: Range<DisplayRow>,
 8916        line_layouts: &[LineWithInvisibles],
 8917        line_height: Pixels,
 8918        scroll_pixel_position: gpui::Point<Pixels>,
 8919        newest_selection_head: Option<DisplayPoint>,
 8920        editor_width: Pixels,
 8921        style: &EditorStyle,
 8922        edits: &Vec<(Range<Anchor>, String)>,
 8923        edit_preview: &Option<language::EditPreview>,
 8924        snapshot: &language::BufferSnapshot,
 8925        window: &mut Window,
 8926        cx: &mut App,
 8927    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8928        let edit_start = edits
 8929            .first()
 8930            .unwrap()
 8931            .0
 8932            .start
 8933            .to_display_point(editor_snapshot);
 8934        let edit_end = edits
 8935            .last()
 8936            .unwrap()
 8937            .0
 8938            .end
 8939            .to_display_point(editor_snapshot);
 8940
 8941        let is_visible = visible_row_range.contains(&edit_start.row())
 8942            || visible_row_range.contains(&edit_end.row());
 8943        if !is_visible {
 8944            return None;
 8945        }
 8946
 8947        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8948            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8949        } else {
 8950            // Fallback for providers without edit_preview
 8951            crate::edit_prediction_fallback_text(edits, cx)
 8952        };
 8953
 8954        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8955        let line_count = highlighted_edits.text.lines().count();
 8956
 8957        const BORDER_WIDTH: Pixels = px(1.);
 8958
 8959        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8960        let has_keybind = keybind.is_some();
 8961
 8962        let mut element = h_flex()
 8963            .items_start()
 8964            .child(
 8965                h_flex()
 8966                    .bg(cx.theme().colors().editor_background)
 8967                    .border(BORDER_WIDTH)
 8968                    .shadow_xs()
 8969                    .border_color(cx.theme().colors().border)
 8970                    .rounded_l_lg()
 8971                    .when(line_count > 1, |el| el.rounded_br_lg())
 8972                    .pr_1()
 8973                    .child(styled_text),
 8974            )
 8975            .child(
 8976                h_flex()
 8977                    .h(line_height + BORDER_WIDTH * 2.)
 8978                    .px_1p5()
 8979                    .gap_1()
 8980                    // Workaround: For some reason, there's a gap if we don't do this
 8981                    .ml(-BORDER_WIDTH)
 8982                    .shadow(vec![gpui::BoxShadow {
 8983                        color: gpui::black().opacity(0.05),
 8984                        offset: point(px(1.), px(1.)),
 8985                        blur_radius: px(2.),
 8986                        spread_radius: px(0.),
 8987                    }])
 8988                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8989                    .border(BORDER_WIDTH)
 8990                    .border_color(cx.theme().colors().border)
 8991                    .rounded_r_lg()
 8992                    .id("edit_prediction_diff_popover_keybind")
 8993                    .when(!has_keybind, |el| {
 8994                        let status_colors = cx.theme().status();
 8995
 8996                        el.bg(status_colors.error_background)
 8997                            .border_color(status_colors.error.opacity(0.6))
 8998                            .child(Icon::new(IconName::Info).color(Color::Error))
 8999                            .cursor_default()
 9000                            .hoverable_tooltip(move |_window, cx| {
 9001                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9002                            })
 9003                    })
 9004                    .children(keybind),
 9005            )
 9006            .into_any();
 9007
 9008        let longest_row =
 9009            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9010        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9011            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9012        } else {
 9013            layout_line(
 9014                longest_row,
 9015                editor_snapshot,
 9016                style,
 9017                editor_width,
 9018                |_| false,
 9019                window,
 9020                cx,
 9021            )
 9022            .width
 9023        };
 9024
 9025        let viewport_bounds =
 9026            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9027                right: -right_margin,
 9028                ..Default::default()
 9029            });
 9030
 9031        let x_after_longest =
 9032            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9033                - scroll_pixel_position.x;
 9034
 9035        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9036
 9037        // Fully visible if it can be displayed within the window (allow overlapping other
 9038        // panes). However, this is only allowed if the popover starts within text_bounds.
 9039        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9040            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9041
 9042        let mut origin = if can_position_to_the_right {
 9043            point(
 9044                x_after_longest,
 9045                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9046                    - scroll_pixel_position.y,
 9047            )
 9048        } else {
 9049            let cursor_row = newest_selection_head.map(|head| head.row());
 9050            let above_edit = edit_start
 9051                .row()
 9052                .0
 9053                .checked_sub(line_count as u32)
 9054                .map(DisplayRow);
 9055            let below_edit = Some(edit_end.row() + 1);
 9056            let above_cursor =
 9057                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9058            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9059
 9060            // Place the edit popover adjacent to the edit if there is a location
 9061            // available that is onscreen and does not obscure the cursor. Otherwise,
 9062            // place it adjacent to the cursor.
 9063            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9064                .into_iter()
 9065                .flatten()
 9066                .find(|&start_row| {
 9067                    let end_row = start_row + line_count as u32;
 9068                    visible_row_range.contains(&start_row)
 9069                        && visible_row_range.contains(&end_row)
 9070                        && cursor_row
 9071                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9072                })?;
 9073
 9074            content_origin
 9075                + point(
 9076                    -scroll_pixel_position.x,
 9077                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9078                )
 9079        };
 9080
 9081        origin.x -= BORDER_WIDTH;
 9082
 9083        window.defer_draw(element, origin, 1);
 9084
 9085        // Do not return an element, since it will already be drawn due to defer_draw.
 9086        None
 9087    }
 9088
 9089    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9090        px(30.)
 9091    }
 9092
 9093    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9094        if self.read_only(cx) {
 9095            cx.theme().players().read_only()
 9096        } else {
 9097            self.style.as_ref().unwrap().local_player
 9098        }
 9099    }
 9100
 9101    fn render_edit_prediction_accept_keybind(
 9102        &self,
 9103        window: &mut Window,
 9104        cx: &App,
 9105    ) -> Option<AnyElement> {
 9106        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9107        let accept_keystroke = accept_binding.keystroke()?;
 9108
 9109        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9110
 9111        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9112            Color::Accent
 9113        } else {
 9114            Color::Muted
 9115        };
 9116
 9117        h_flex()
 9118            .px_0p5()
 9119            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9120            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9121            .text_size(TextSize::XSmall.rems(cx))
 9122            .child(h_flex().children(ui::render_modifiers(
 9123                accept_keystroke.modifiers(),
 9124                PlatformStyle::platform(),
 9125                Some(modifiers_color),
 9126                Some(IconSize::XSmall.rems().into()),
 9127                true,
 9128            )))
 9129            .when(is_platform_style_mac, |parent| {
 9130                parent.child(accept_keystroke.key().to_string())
 9131            })
 9132            .when(!is_platform_style_mac, |parent| {
 9133                parent.child(
 9134                    Key::new(
 9135                        util::capitalize(accept_keystroke.key()),
 9136                        Some(Color::Default),
 9137                    )
 9138                    .size(Some(IconSize::XSmall.rems().into())),
 9139                )
 9140            })
 9141            .into_any()
 9142            .into()
 9143    }
 9144
 9145    fn render_edit_prediction_line_popover(
 9146        &self,
 9147        label: impl Into<SharedString>,
 9148        icon: Option<IconName>,
 9149        window: &mut Window,
 9150        cx: &App,
 9151    ) -> Option<Stateful<Div>> {
 9152        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9153
 9154        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9155        let has_keybind = keybind.is_some();
 9156
 9157        let result = h_flex()
 9158            .id("ep-line-popover")
 9159            .py_0p5()
 9160            .pl_1()
 9161            .pr(padding_right)
 9162            .gap_1()
 9163            .rounded_md()
 9164            .border_1()
 9165            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9166            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9167            .shadow_xs()
 9168            .when(!has_keybind, |el| {
 9169                let status_colors = cx.theme().status();
 9170
 9171                el.bg(status_colors.error_background)
 9172                    .border_color(status_colors.error.opacity(0.6))
 9173                    .pl_2()
 9174                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9175                    .cursor_default()
 9176                    .hoverable_tooltip(move |_window, cx| {
 9177                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9178                    })
 9179            })
 9180            .children(keybind)
 9181            .child(
 9182                Label::new(label)
 9183                    .size(LabelSize::Small)
 9184                    .when(!has_keybind, |el| {
 9185                        el.color(cx.theme().status().error.into()).strikethrough()
 9186                    }),
 9187            )
 9188            .when(!has_keybind, |el| {
 9189                el.child(
 9190                    h_flex().ml_1().child(
 9191                        Icon::new(IconName::Info)
 9192                            .size(IconSize::Small)
 9193                            .color(cx.theme().status().error.into()),
 9194                    ),
 9195                )
 9196            })
 9197            .when_some(icon, |element, icon| {
 9198                element.child(
 9199                    div()
 9200                        .mt(px(1.5))
 9201                        .child(Icon::new(icon).size(IconSize::Small)),
 9202                )
 9203            });
 9204
 9205        Some(result)
 9206    }
 9207
 9208    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9209        let accent_color = cx.theme().colors().text_accent;
 9210        let editor_bg_color = cx.theme().colors().editor_background;
 9211        editor_bg_color.blend(accent_color.opacity(0.1))
 9212    }
 9213
 9214    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9215        let accent_color = cx.theme().colors().text_accent;
 9216        let editor_bg_color = cx.theme().colors().editor_background;
 9217        editor_bg_color.blend(accent_color.opacity(0.6))
 9218    }
 9219    fn get_prediction_provider_icon_name(
 9220        provider: &Option<RegisteredEditPredictionProvider>,
 9221    ) -> IconName {
 9222        match provider {
 9223            Some(provider) => match provider.provider.name() {
 9224                "copilot" => IconName::Copilot,
 9225                "supermaven" => IconName::Supermaven,
 9226                _ => IconName::ZedPredict,
 9227            },
 9228            None => IconName::ZedPredict,
 9229        }
 9230    }
 9231
 9232    fn render_edit_prediction_cursor_popover(
 9233        &self,
 9234        min_width: Pixels,
 9235        max_width: Pixels,
 9236        cursor_point: Point,
 9237        style: &EditorStyle,
 9238        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9239        _window: &Window,
 9240        cx: &mut Context<Editor>,
 9241    ) -> Option<AnyElement> {
 9242        let provider = self.edit_prediction_provider.as_ref()?;
 9243        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9244
 9245        let is_refreshing = provider.provider.is_refreshing(cx);
 9246
 9247        fn pending_completion_container(icon: IconName) -> Div {
 9248            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9249        }
 9250
 9251        let completion = match &self.active_edit_prediction {
 9252            Some(prediction) => {
 9253                if !self.has_visible_completions_menu() {
 9254                    const RADIUS: Pixels = px(6.);
 9255                    const BORDER_WIDTH: Pixels = px(1.);
 9256
 9257                    return Some(
 9258                        h_flex()
 9259                            .elevation_2(cx)
 9260                            .border(BORDER_WIDTH)
 9261                            .border_color(cx.theme().colors().border)
 9262                            .when(accept_keystroke.is_none(), |el| {
 9263                                el.border_color(cx.theme().status().error)
 9264                            })
 9265                            .rounded(RADIUS)
 9266                            .rounded_tl(px(0.))
 9267                            .overflow_hidden()
 9268                            .child(div().px_1p5().child(match &prediction.completion {
 9269                                EditPrediction::Move { target, snapshot } => {
 9270                                    use text::ToPoint as _;
 9271                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9272                                    {
 9273                                        Icon::new(IconName::ZedPredictDown)
 9274                                    } else {
 9275                                        Icon::new(IconName::ZedPredictUp)
 9276                                    }
 9277                                }
 9278                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9279                            }))
 9280                            .child(
 9281                                h_flex()
 9282                                    .gap_1()
 9283                                    .py_1()
 9284                                    .px_2()
 9285                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9286                                    .border_l_1()
 9287                                    .border_color(cx.theme().colors().border)
 9288                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9289                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9290                                        el.child(
 9291                                            Label::new("Hold")
 9292                                                .size(LabelSize::Small)
 9293                                                .when(accept_keystroke.is_none(), |el| {
 9294                                                    el.strikethrough()
 9295                                                })
 9296                                                .line_height_style(LineHeightStyle::UiLabel),
 9297                                        )
 9298                                    })
 9299                                    .id("edit_prediction_cursor_popover_keybind")
 9300                                    .when(accept_keystroke.is_none(), |el| {
 9301                                        let status_colors = cx.theme().status();
 9302
 9303                                        el.bg(status_colors.error_background)
 9304                                            .border_color(status_colors.error.opacity(0.6))
 9305                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9306                                            .cursor_default()
 9307                                            .hoverable_tooltip(move |_window, cx| {
 9308                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9309                                                    .into()
 9310                                            })
 9311                                    })
 9312                                    .when_some(
 9313                                        accept_keystroke.as_ref(),
 9314                                        |el, accept_keystroke| {
 9315                                            el.child(h_flex().children(ui::render_modifiers(
 9316                                                accept_keystroke.modifiers(),
 9317                                                PlatformStyle::platform(),
 9318                                                Some(Color::Default),
 9319                                                Some(IconSize::XSmall.rems().into()),
 9320                                                false,
 9321                                            )))
 9322                                        },
 9323                                    ),
 9324                            )
 9325                            .into_any(),
 9326                    );
 9327                }
 9328
 9329                self.render_edit_prediction_cursor_popover_preview(
 9330                    prediction,
 9331                    cursor_point,
 9332                    style,
 9333                    cx,
 9334                )?
 9335            }
 9336
 9337            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9338                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9339                    stale_completion,
 9340                    cursor_point,
 9341                    style,
 9342                    cx,
 9343                )?,
 9344
 9345                None => pending_completion_container(provider_icon)
 9346                    .child(Label::new("...").size(LabelSize::Small)),
 9347            },
 9348
 9349            None => pending_completion_container(provider_icon)
 9350                .child(Label::new("...").size(LabelSize::Small)),
 9351        };
 9352
 9353        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9354            completion
 9355                .with_animation(
 9356                    "loading-completion",
 9357                    Animation::new(Duration::from_secs(2))
 9358                        .repeat()
 9359                        .with_easing(pulsating_between(0.4, 0.8)),
 9360                    |label, delta| label.opacity(delta),
 9361                )
 9362                .into_any_element()
 9363        } else {
 9364            completion.into_any_element()
 9365        };
 9366
 9367        let has_completion = self.active_edit_prediction.is_some();
 9368
 9369        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9370        Some(
 9371            h_flex()
 9372                .min_w(min_width)
 9373                .max_w(max_width)
 9374                .flex_1()
 9375                .elevation_2(cx)
 9376                .border_color(cx.theme().colors().border)
 9377                .child(
 9378                    div()
 9379                        .flex_1()
 9380                        .py_1()
 9381                        .px_2()
 9382                        .overflow_hidden()
 9383                        .child(completion),
 9384                )
 9385                .when_some(accept_keystroke, |el, accept_keystroke| {
 9386                    if !accept_keystroke.modifiers().modified() {
 9387                        return el;
 9388                    }
 9389
 9390                    el.child(
 9391                        h_flex()
 9392                            .h_full()
 9393                            .border_l_1()
 9394                            .rounded_r_lg()
 9395                            .border_color(cx.theme().colors().border)
 9396                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9397                            .gap_1()
 9398                            .py_1()
 9399                            .px_2()
 9400                            .child(
 9401                                h_flex()
 9402                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9403                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9404                                    .child(h_flex().children(ui::render_modifiers(
 9405                                        accept_keystroke.modifiers(),
 9406                                        PlatformStyle::platform(),
 9407                                        Some(if !has_completion {
 9408                                            Color::Muted
 9409                                        } else {
 9410                                            Color::Default
 9411                                        }),
 9412                                        None,
 9413                                        false,
 9414                                    ))),
 9415                            )
 9416                            .child(Label::new("Preview").into_any_element())
 9417                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9418                    )
 9419                })
 9420                .into_any(),
 9421        )
 9422    }
 9423
 9424    fn render_edit_prediction_cursor_popover_preview(
 9425        &self,
 9426        completion: &EditPredictionState,
 9427        cursor_point: Point,
 9428        style: &EditorStyle,
 9429        cx: &mut Context<Editor>,
 9430    ) -> Option<Div> {
 9431        use text::ToPoint as _;
 9432
 9433        fn render_relative_row_jump(
 9434            prefix: impl Into<String>,
 9435            current_row: u32,
 9436            target_row: u32,
 9437        ) -> Div {
 9438            let (row_diff, arrow) = if target_row < current_row {
 9439                (current_row - target_row, IconName::ArrowUp)
 9440            } else {
 9441                (target_row - current_row, IconName::ArrowDown)
 9442            };
 9443
 9444            h_flex()
 9445                .child(
 9446                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9447                        .color(Color::Muted)
 9448                        .size(LabelSize::Small),
 9449                )
 9450                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9451        }
 9452
 9453        let supports_jump = self
 9454            .edit_prediction_provider
 9455            .as_ref()
 9456            .map(|provider| provider.provider.supports_jump_to_edit())
 9457            .unwrap_or(true);
 9458
 9459        match &completion.completion {
 9460            EditPrediction::Move {
 9461                target, snapshot, ..
 9462            } => {
 9463                if !supports_jump {
 9464                    return None;
 9465                }
 9466
 9467                Some(
 9468                    h_flex()
 9469                        .px_2()
 9470                        .gap_2()
 9471                        .flex_1()
 9472                        .child(
 9473                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9474                                Icon::new(IconName::ZedPredictDown)
 9475                            } else {
 9476                                Icon::new(IconName::ZedPredictUp)
 9477                            },
 9478                        )
 9479                        .child(Label::new("Jump to Edit")),
 9480                )
 9481            }
 9482
 9483            EditPrediction::Edit {
 9484                edits,
 9485                edit_preview,
 9486                snapshot,
 9487                display_mode: _,
 9488            } => {
 9489                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9490
 9491                let (highlighted_edits, has_more_lines) =
 9492                    if let Some(edit_preview) = edit_preview.as_ref() {
 9493                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9494                            .first_line_preview()
 9495                    } else {
 9496                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9497                    };
 9498
 9499                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9500                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9501
 9502                let preview = h_flex()
 9503                    .gap_1()
 9504                    .min_w_16()
 9505                    .child(styled_text)
 9506                    .when(has_more_lines, |parent| parent.child(""));
 9507
 9508                let left = if supports_jump && first_edit_row != cursor_point.row {
 9509                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9510                        .into_any_element()
 9511                } else {
 9512                    let icon_name =
 9513                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9514                    Icon::new(icon_name).into_any_element()
 9515                };
 9516
 9517                Some(
 9518                    h_flex()
 9519                        .h_full()
 9520                        .flex_1()
 9521                        .gap_2()
 9522                        .pr_1()
 9523                        .overflow_x_hidden()
 9524                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9525                        .child(left)
 9526                        .child(preview),
 9527                )
 9528            }
 9529        }
 9530    }
 9531
 9532    pub fn render_context_menu(
 9533        &self,
 9534        style: &EditorStyle,
 9535        max_height_in_lines: u32,
 9536        window: &mut Window,
 9537        cx: &mut Context<Editor>,
 9538    ) -> Option<AnyElement> {
 9539        let menu = self.context_menu.borrow();
 9540        let menu = menu.as_ref()?;
 9541        if !menu.visible() {
 9542            return None;
 9543        };
 9544        Some(menu.render(style, max_height_in_lines, window, cx))
 9545    }
 9546
 9547    fn render_context_menu_aside(
 9548        &mut self,
 9549        max_size: Size<Pixels>,
 9550        window: &mut Window,
 9551        cx: &mut Context<Editor>,
 9552    ) -> Option<AnyElement> {
 9553        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9554            if menu.visible() {
 9555                menu.render_aside(max_size, window, cx)
 9556            } else {
 9557                None
 9558            }
 9559        })
 9560    }
 9561
 9562    fn hide_context_menu(
 9563        &mut self,
 9564        window: &mut Window,
 9565        cx: &mut Context<Self>,
 9566    ) -> Option<CodeContextMenu> {
 9567        cx.notify();
 9568        self.completion_tasks.clear();
 9569        let context_menu = self.context_menu.borrow_mut().take();
 9570        self.stale_edit_prediction_in_menu.take();
 9571        self.update_visible_edit_prediction(window, cx);
 9572        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9573            && let Some(completion_provider) = &self.completion_provider
 9574        {
 9575            completion_provider.selection_changed(None, window, cx);
 9576        }
 9577        context_menu
 9578    }
 9579
 9580    fn show_snippet_choices(
 9581        &mut self,
 9582        choices: &Vec<String>,
 9583        selection: Range<Anchor>,
 9584        cx: &mut Context<Self>,
 9585    ) {
 9586        let Some((_, buffer, _)) = self
 9587            .buffer()
 9588            .read(cx)
 9589            .excerpt_containing(selection.start, cx)
 9590        else {
 9591            return;
 9592        };
 9593        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9594        else {
 9595            return;
 9596        };
 9597        if buffer != end_buffer {
 9598            log::error!("expected anchor range to have matching buffer IDs");
 9599            return;
 9600        }
 9601
 9602        let id = post_inc(&mut self.next_completion_id);
 9603        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9604        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9605            CompletionsMenu::new_snippet_choices(
 9606                id,
 9607                true,
 9608                choices,
 9609                selection,
 9610                buffer,
 9611                snippet_sort_order,
 9612            ),
 9613        ));
 9614    }
 9615
 9616    pub fn insert_snippet(
 9617        &mut self,
 9618        insertion_ranges: &[Range<usize>],
 9619        snippet: Snippet,
 9620        window: &mut Window,
 9621        cx: &mut Context<Self>,
 9622    ) -> Result<()> {
 9623        struct Tabstop<T> {
 9624            is_end_tabstop: bool,
 9625            ranges: Vec<Range<T>>,
 9626            choices: Option<Vec<String>>,
 9627        }
 9628
 9629        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9630            let snippet_text: Arc<str> = snippet.text.clone().into();
 9631            let edits = insertion_ranges
 9632                .iter()
 9633                .cloned()
 9634                .map(|range| (range, snippet_text.clone()));
 9635            let autoindent_mode = AutoindentMode::Block {
 9636                original_indent_columns: Vec::new(),
 9637            };
 9638            buffer.edit(edits, Some(autoindent_mode), cx);
 9639
 9640            let snapshot = &*buffer.read(cx);
 9641            let snippet = &snippet;
 9642            snippet
 9643                .tabstops
 9644                .iter()
 9645                .map(|tabstop| {
 9646                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9647                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9648                    });
 9649                    let mut tabstop_ranges = tabstop
 9650                        .ranges
 9651                        .iter()
 9652                        .flat_map(|tabstop_range| {
 9653                            let mut delta = 0_isize;
 9654                            insertion_ranges.iter().map(move |insertion_range| {
 9655                                let insertion_start = insertion_range.start as isize + delta;
 9656                                delta +=
 9657                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9658
 9659                                let start = ((insertion_start + tabstop_range.start) as usize)
 9660                                    .min(snapshot.len());
 9661                                let end = ((insertion_start + tabstop_range.end) as usize)
 9662                                    .min(snapshot.len());
 9663                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9664                            })
 9665                        })
 9666                        .collect::<Vec<_>>();
 9667                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9668
 9669                    Tabstop {
 9670                        is_end_tabstop,
 9671                        ranges: tabstop_ranges,
 9672                        choices: tabstop.choices.clone(),
 9673                    }
 9674                })
 9675                .collect::<Vec<_>>()
 9676        });
 9677        if let Some(tabstop) = tabstops.first() {
 9678            self.change_selections(Default::default(), window, cx, |s| {
 9679                // Reverse order so that the first range is the newest created selection.
 9680                // Completions will use it and autoscroll will prioritize it.
 9681                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9682            });
 9683
 9684            if let Some(choices) = &tabstop.choices
 9685                && let Some(selection) = tabstop.ranges.first()
 9686            {
 9687                self.show_snippet_choices(choices, selection.clone(), cx)
 9688            }
 9689
 9690            // If we're already at the last tabstop and it's at the end of the snippet,
 9691            // we're done, we don't need to keep the state around.
 9692            if !tabstop.is_end_tabstop {
 9693                let choices = tabstops
 9694                    .iter()
 9695                    .map(|tabstop| tabstop.choices.clone())
 9696                    .collect();
 9697
 9698                let ranges = tabstops
 9699                    .into_iter()
 9700                    .map(|tabstop| tabstop.ranges)
 9701                    .collect::<Vec<_>>();
 9702
 9703                self.snippet_stack.push(SnippetState {
 9704                    active_index: 0,
 9705                    ranges,
 9706                    choices,
 9707                });
 9708            }
 9709
 9710            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9711            if self.autoclose_regions.is_empty() {
 9712                let snapshot = self.buffer.read(cx).snapshot(cx);
 9713                let mut all_selections = self.selections.all::<Point>(cx);
 9714                for selection in &mut all_selections {
 9715                    let selection_head = selection.head();
 9716                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9717                        continue;
 9718                    };
 9719
 9720                    let mut bracket_pair = None;
 9721                    let max_lookup_length = scope
 9722                        .brackets()
 9723                        .map(|(pair, _)| {
 9724                            pair.start
 9725                                .as_str()
 9726                                .chars()
 9727                                .count()
 9728                                .max(pair.end.as_str().chars().count())
 9729                        })
 9730                        .max();
 9731                    if let Some(max_lookup_length) = max_lookup_length {
 9732                        let next_text = snapshot
 9733                            .chars_at(selection_head)
 9734                            .take(max_lookup_length)
 9735                            .collect::<String>();
 9736                        let prev_text = snapshot
 9737                            .reversed_chars_at(selection_head)
 9738                            .take(max_lookup_length)
 9739                            .collect::<String>();
 9740
 9741                        for (pair, enabled) in scope.brackets() {
 9742                            if enabled
 9743                                && pair.close
 9744                                && prev_text.starts_with(pair.start.as_str())
 9745                                && next_text.starts_with(pair.end.as_str())
 9746                            {
 9747                                bracket_pair = Some(pair.clone());
 9748                                break;
 9749                            }
 9750                        }
 9751                    }
 9752
 9753                    if let Some(pair) = bracket_pair {
 9754                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9755                        let autoclose_enabled =
 9756                            self.use_autoclose && snapshot_settings.use_autoclose;
 9757                        if autoclose_enabled {
 9758                            let start = snapshot.anchor_after(selection_head);
 9759                            let end = snapshot.anchor_after(selection_head);
 9760                            self.autoclose_regions.push(AutocloseRegion {
 9761                                selection_id: selection.id,
 9762                                range: start..end,
 9763                                pair,
 9764                            });
 9765                        }
 9766                    }
 9767                }
 9768            }
 9769        }
 9770        Ok(())
 9771    }
 9772
 9773    pub fn move_to_next_snippet_tabstop(
 9774        &mut self,
 9775        window: &mut Window,
 9776        cx: &mut Context<Self>,
 9777    ) -> bool {
 9778        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9779    }
 9780
 9781    pub fn move_to_prev_snippet_tabstop(
 9782        &mut self,
 9783        window: &mut Window,
 9784        cx: &mut Context<Self>,
 9785    ) -> bool {
 9786        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9787    }
 9788
 9789    pub fn move_to_snippet_tabstop(
 9790        &mut self,
 9791        bias: Bias,
 9792        window: &mut Window,
 9793        cx: &mut Context<Self>,
 9794    ) -> bool {
 9795        if let Some(mut snippet) = self.snippet_stack.pop() {
 9796            match bias {
 9797                Bias::Left => {
 9798                    if snippet.active_index > 0 {
 9799                        snippet.active_index -= 1;
 9800                    } else {
 9801                        self.snippet_stack.push(snippet);
 9802                        return false;
 9803                    }
 9804                }
 9805                Bias::Right => {
 9806                    if snippet.active_index + 1 < snippet.ranges.len() {
 9807                        snippet.active_index += 1;
 9808                    } else {
 9809                        self.snippet_stack.push(snippet);
 9810                        return false;
 9811                    }
 9812                }
 9813            }
 9814            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9815                self.change_selections(Default::default(), window, cx, |s| {
 9816                    // Reverse order so that the first range is the newest created selection.
 9817                    // Completions will use it and autoscroll will prioritize it.
 9818                    s.select_ranges(current_ranges.iter().rev().cloned())
 9819                });
 9820
 9821                if let Some(choices) = &snippet.choices[snippet.active_index]
 9822                    && let Some(selection) = current_ranges.first()
 9823                {
 9824                    self.show_snippet_choices(choices, selection.clone(), cx);
 9825                }
 9826
 9827                // If snippet state is not at the last tabstop, push it back on the stack
 9828                if snippet.active_index + 1 < snippet.ranges.len() {
 9829                    self.snippet_stack.push(snippet);
 9830                }
 9831                return true;
 9832            }
 9833        }
 9834
 9835        false
 9836    }
 9837
 9838    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9839        self.transact(window, cx, |this, window, cx| {
 9840            this.select_all(&SelectAll, window, cx);
 9841            this.insert("", window, cx);
 9842        });
 9843    }
 9844
 9845    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9846        if self.read_only(cx) {
 9847            return;
 9848        }
 9849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9850        self.transact(window, cx, |this, window, cx| {
 9851            this.select_autoclose_pair(window, cx);
 9852            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9853            if !this.linked_edit_ranges.is_empty() {
 9854                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9855                let snapshot = this.buffer.read(cx).snapshot(cx);
 9856
 9857                for selection in selections.iter() {
 9858                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9859                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9860                    if selection_start.buffer_id != selection_end.buffer_id {
 9861                        continue;
 9862                    }
 9863                    if let Some(ranges) =
 9864                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9865                    {
 9866                        for (buffer, entries) in ranges {
 9867                            linked_ranges.entry(buffer).or_default().extend(entries);
 9868                        }
 9869                    }
 9870                }
 9871            }
 9872
 9873            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9874            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9875            for selection in &mut selections {
 9876                if selection.is_empty() {
 9877                    let old_head = selection.head();
 9878                    let mut new_head =
 9879                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9880                            .to_point(&display_map);
 9881                    if let Some((buffer, line_buffer_range)) = display_map
 9882                        .buffer_snapshot
 9883                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9884                    {
 9885                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9886                        let indent_len = match indent_size.kind {
 9887                            IndentKind::Space => {
 9888                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9889                            }
 9890                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9891                        };
 9892                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9893                            let indent_len = indent_len.get();
 9894                            new_head = cmp::min(
 9895                                new_head,
 9896                                MultiBufferPoint::new(
 9897                                    old_head.row,
 9898                                    ((old_head.column - 1) / indent_len) * indent_len,
 9899                                ),
 9900                            );
 9901                        }
 9902                    }
 9903
 9904                    selection.set_head(new_head, SelectionGoal::None);
 9905                }
 9906            }
 9907
 9908            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9909            this.insert("", window, cx);
 9910            let empty_str: Arc<str> = Arc::from("");
 9911            for (buffer, edits) in linked_ranges {
 9912                let snapshot = buffer.read(cx).snapshot();
 9913                use text::ToPoint as TP;
 9914
 9915                let edits = edits
 9916                    .into_iter()
 9917                    .map(|range| {
 9918                        let end_point = TP::to_point(&range.end, &snapshot);
 9919                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9920
 9921                        if end_point == start_point {
 9922                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9923                                .saturating_sub(1);
 9924                            start_point =
 9925                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9926                        };
 9927
 9928                        (start_point..end_point, empty_str.clone())
 9929                    })
 9930                    .sorted_by_key(|(range, _)| range.start)
 9931                    .collect::<Vec<_>>();
 9932                buffer.update(cx, |this, cx| {
 9933                    this.edit(edits, None, cx);
 9934                })
 9935            }
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9938        });
 9939    }
 9940
 9941    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9942        if self.read_only(cx) {
 9943            return;
 9944        }
 9945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9946        self.transact(window, cx, |this, window, cx| {
 9947            this.change_selections(Default::default(), window, cx, |s| {
 9948                s.move_with(|map, selection| {
 9949                    if selection.is_empty() {
 9950                        let cursor = movement::right(map, selection.head());
 9951                        selection.end = cursor;
 9952                        selection.reversed = true;
 9953                        selection.goal = SelectionGoal::None;
 9954                    }
 9955                })
 9956            });
 9957            this.insert("", window, cx);
 9958            this.refresh_edit_prediction(true, false, window, cx);
 9959        });
 9960    }
 9961
 9962    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9963        if self.mode.is_single_line() {
 9964            cx.propagate();
 9965            return;
 9966        }
 9967
 9968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9969        if self.move_to_prev_snippet_tabstop(window, cx) {
 9970            return;
 9971        }
 9972        self.outdent(&Outdent, window, cx);
 9973    }
 9974
 9975    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9976        if self.mode.is_single_line() {
 9977            cx.propagate();
 9978            return;
 9979        }
 9980
 9981        if self.move_to_next_snippet_tabstop(window, cx) {
 9982            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9983            return;
 9984        }
 9985        if self.read_only(cx) {
 9986            return;
 9987        }
 9988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9989        let mut selections = self.selections.all_adjusted(cx);
 9990        let buffer = self.buffer.read(cx);
 9991        let snapshot = buffer.snapshot(cx);
 9992        let rows_iter = selections.iter().map(|s| s.head().row);
 9993        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9994
 9995        let has_some_cursor_in_whitespace = selections
 9996            .iter()
 9997            .filter(|selection| selection.is_empty())
 9998            .any(|selection| {
 9999                let cursor = selection.head();
10000                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10001                cursor.column < current_indent.len
10002            });
10003
10004        let mut edits = Vec::new();
10005        let mut prev_edited_row = 0;
10006        let mut row_delta = 0;
10007        for selection in &mut selections {
10008            if selection.start.row != prev_edited_row {
10009                row_delta = 0;
10010            }
10011            prev_edited_row = selection.end.row;
10012
10013            // If the selection is non-empty, then increase the indentation of the selected lines.
10014            if !selection.is_empty() {
10015                row_delta =
10016                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10017                continue;
10018            }
10019
10020            let cursor = selection.head();
10021            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10022            if let Some(suggested_indent) =
10023                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10024            {
10025                // Don't do anything if already at suggested indent
10026                // and there is any other cursor which is not
10027                if has_some_cursor_in_whitespace
10028                    && cursor.column == current_indent.len
10029                    && current_indent.len == suggested_indent.len
10030                {
10031                    continue;
10032                }
10033
10034                // Adjust line and move cursor to suggested indent
10035                // if cursor is not at suggested indent
10036                if cursor.column < suggested_indent.len
10037                    && cursor.column <= current_indent.len
10038                    && current_indent.len <= suggested_indent.len
10039                {
10040                    selection.start = Point::new(cursor.row, suggested_indent.len);
10041                    selection.end = selection.start;
10042                    if row_delta == 0 {
10043                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10044                            cursor.row,
10045                            current_indent,
10046                            suggested_indent,
10047                        ));
10048                        row_delta = suggested_indent.len - current_indent.len;
10049                    }
10050                    continue;
10051                }
10052
10053                // If current indent is more than suggested indent
10054                // only move cursor to current indent and skip indent
10055                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10056                    selection.start = Point::new(cursor.row, current_indent.len);
10057                    selection.end = selection.start;
10058                    continue;
10059                }
10060            }
10061
10062            // Otherwise, insert a hard or soft tab.
10063            let settings = buffer.language_settings_at(cursor, cx);
10064            let tab_size = if settings.hard_tabs {
10065                IndentSize::tab()
10066            } else {
10067                let tab_size = settings.tab_size.get();
10068                let indent_remainder = snapshot
10069                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10070                    .flat_map(str::chars)
10071                    .fold(row_delta % tab_size, |counter: u32, c| {
10072                        if c == '\t' {
10073                            0
10074                        } else {
10075                            (counter + 1) % tab_size
10076                        }
10077                    });
10078
10079                let chars_to_next_tab_stop = tab_size - indent_remainder;
10080                IndentSize::spaces(chars_to_next_tab_stop)
10081            };
10082            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10083            selection.end = selection.start;
10084            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10085            row_delta += tab_size.len;
10086        }
10087
10088        self.transact(window, cx, |this, window, cx| {
10089            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10090            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10091            this.refresh_edit_prediction(true, false, window, cx);
10092        });
10093    }
10094
10095    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10096        if self.read_only(cx) {
10097            return;
10098        }
10099        if self.mode.is_single_line() {
10100            cx.propagate();
10101            return;
10102        }
10103
10104        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10105        let mut selections = self.selections.all::<Point>(cx);
10106        let mut prev_edited_row = 0;
10107        let mut row_delta = 0;
10108        let mut edits = Vec::new();
10109        let buffer = self.buffer.read(cx);
10110        let snapshot = buffer.snapshot(cx);
10111        for selection in &mut selections {
10112            if selection.start.row != prev_edited_row {
10113                row_delta = 0;
10114            }
10115            prev_edited_row = selection.end.row;
10116
10117            row_delta =
10118                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10119        }
10120
10121        self.transact(window, cx, |this, window, cx| {
10122            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10123            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10124        });
10125    }
10126
10127    fn indent_selection(
10128        buffer: &MultiBuffer,
10129        snapshot: &MultiBufferSnapshot,
10130        selection: &mut Selection<Point>,
10131        edits: &mut Vec<(Range<Point>, String)>,
10132        delta_for_start_row: u32,
10133        cx: &App,
10134    ) -> u32 {
10135        let settings = buffer.language_settings_at(selection.start, cx);
10136        let tab_size = settings.tab_size.get();
10137        let indent_kind = if settings.hard_tabs {
10138            IndentKind::Tab
10139        } else {
10140            IndentKind::Space
10141        };
10142        let mut start_row = selection.start.row;
10143        let mut end_row = selection.end.row + 1;
10144
10145        // If a selection ends at the beginning of a line, don't indent
10146        // that last line.
10147        if selection.end.column == 0 && selection.end.row > selection.start.row {
10148            end_row -= 1;
10149        }
10150
10151        // Avoid re-indenting a row that has already been indented by a
10152        // previous selection, but still update this selection's column
10153        // to reflect that indentation.
10154        if delta_for_start_row > 0 {
10155            start_row += 1;
10156            selection.start.column += delta_for_start_row;
10157            if selection.end.row == selection.start.row {
10158                selection.end.column += delta_for_start_row;
10159            }
10160        }
10161
10162        let mut delta_for_end_row = 0;
10163        let has_multiple_rows = start_row + 1 != end_row;
10164        for row in start_row..end_row {
10165            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10166            let indent_delta = match (current_indent.kind, indent_kind) {
10167                (IndentKind::Space, IndentKind::Space) => {
10168                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10169                    IndentSize::spaces(columns_to_next_tab_stop)
10170                }
10171                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10172                (_, IndentKind::Tab) => IndentSize::tab(),
10173            };
10174
10175            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10176                0
10177            } else {
10178                selection.start.column
10179            };
10180            let row_start = Point::new(row, start);
10181            edits.push((
10182                row_start..row_start,
10183                indent_delta.chars().collect::<String>(),
10184            ));
10185
10186            // Update this selection's endpoints to reflect the indentation.
10187            if row == selection.start.row {
10188                selection.start.column += indent_delta.len;
10189            }
10190            if row == selection.end.row {
10191                selection.end.column += indent_delta.len;
10192                delta_for_end_row = indent_delta.len;
10193            }
10194        }
10195
10196        if selection.start.row == selection.end.row {
10197            delta_for_start_row + delta_for_end_row
10198        } else {
10199            delta_for_end_row
10200        }
10201    }
10202
10203    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10204        if self.read_only(cx) {
10205            return;
10206        }
10207        if self.mode.is_single_line() {
10208            cx.propagate();
10209            return;
10210        }
10211
10212        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10213        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10214        let selections = self.selections.all::<Point>(cx);
10215        let mut deletion_ranges = Vec::new();
10216        let mut last_outdent = None;
10217        {
10218            let buffer = self.buffer.read(cx);
10219            let snapshot = buffer.snapshot(cx);
10220            for selection in &selections {
10221                let settings = buffer.language_settings_at(selection.start, cx);
10222                let tab_size = settings.tab_size.get();
10223                let mut rows = selection.spanned_rows(false, &display_map);
10224
10225                // Avoid re-outdenting a row that has already been outdented by a
10226                // previous selection.
10227                if let Some(last_row) = last_outdent
10228                    && last_row == rows.start
10229                {
10230                    rows.start = rows.start.next_row();
10231                }
10232                let has_multiple_rows = rows.len() > 1;
10233                for row in rows.iter_rows() {
10234                    let indent_size = snapshot.indent_size_for_line(row);
10235                    if indent_size.len > 0 {
10236                        let deletion_len = match indent_size.kind {
10237                            IndentKind::Space => {
10238                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10239                                if columns_to_prev_tab_stop == 0 {
10240                                    tab_size
10241                                } else {
10242                                    columns_to_prev_tab_stop
10243                                }
10244                            }
10245                            IndentKind::Tab => 1,
10246                        };
10247                        let start = if has_multiple_rows
10248                            || deletion_len > selection.start.column
10249                            || indent_size.len < selection.start.column
10250                        {
10251                            0
10252                        } else {
10253                            selection.start.column - deletion_len
10254                        };
10255                        deletion_ranges.push(
10256                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10257                        );
10258                        last_outdent = Some(row);
10259                    }
10260                }
10261            }
10262        }
10263
10264        self.transact(window, cx, |this, window, cx| {
10265            this.buffer.update(cx, |buffer, cx| {
10266                let empty_str: Arc<str> = Arc::default();
10267                buffer.edit(
10268                    deletion_ranges
10269                        .into_iter()
10270                        .map(|range| (range, empty_str.clone())),
10271                    None,
10272                    cx,
10273                );
10274            });
10275            let selections = this.selections.all::<usize>(cx);
10276            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10277        });
10278    }
10279
10280    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10281        if self.read_only(cx) {
10282            return;
10283        }
10284        if self.mode.is_single_line() {
10285            cx.propagate();
10286            return;
10287        }
10288
10289        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10290        let selections = self
10291            .selections
10292            .all::<usize>(cx)
10293            .into_iter()
10294            .map(|s| s.range());
10295
10296        self.transact(window, cx, |this, window, cx| {
10297            this.buffer.update(cx, |buffer, cx| {
10298                buffer.autoindent_ranges(selections, cx);
10299            });
10300            let selections = this.selections.all::<usize>(cx);
10301            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10302        });
10303    }
10304
10305    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10307        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10308        let selections = self.selections.all::<Point>(cx);
10309
10310        let mut new_cursors = Vec::new();
10311        let mut edit_ranges = Vec::new();
10312        let mut selections = selections.iter().peekable();
10313        while let Some(selection) = selections.next() {
10314            let mut rows = selection.spanned_rows(false, &display_map);
10315            let goal_display_column = selection.head().to_display_point(&display_map).column();
10316
10317            // Accumulate contiguous regions of rows that we want to delete.
10318            while let Some(next_selection) = selections.peek() {
10319                let next_rows = next_selection.spanned_rows(false, &display_map);
10320                if next_rows.start <= rows.end {
10321                    rows.end = next_rows.end;
10322                    selections.next().unwrap();
10323                } else {
10324                    break;
10325                }
10326            }
10327
10328            let buffer = &display_map.buffer_snapshot;
10329            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10330            let edit_end;
10331            let cursor_buffer_row;
10332            if buffer.max_point().row >= rows.end.0 {
10333                // If there's a line after the range, delete the \n from the end of the row range
10334                // and position the cursor on the next line.
10335                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10336                cursor_buffer_row = rows.end;
10337            } else {
10338                // If there isn't a line after the range, delete the \n from the line before the
10339                // start of the row range and position the cursor there.
10340                edit_start = edit_start.saturating_sub(1);
10341                edit_end = buffer.len();
10342                cursor_buffer_row = rows.start.previous_row();
10343            }
10344
10345            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10346            *cursor.column_mut() =
10347                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10348
10349            new_cursors.push((
10350                selection.id,
10351                buffer.anchor_after(cursor.to_point(&display_map)),
10352            ));
10353            edit_ranges.push(edit_start..edit_end);
10354        }
10355
10356        self.transact(window, cx, |this, window, cx| {
10357            let buffer = this.buffer.update(cx, |buffer, cx| {
10358                let empty_str: Arc<str> = Arc::default();
10359                buffer.edit(
10360                    edit_ranges
10361                        .into_iter()
10362                        .map(|range| (range, empty_str.clone())),
10363                    None,
10364                    cx,
10365                );
10366                buffer.snapshot(cx)
10367            });
10368            let new_selections = new_cursors
10369                .into_iter()
10370                .map(|(id, cursor)| {
10371                    let cursor = cursor.to_point(&buffer);
10372                    Selection {
10373                        id,
10374                        start: cursor,
10375                        end: cursor,
10376                        reversed: false,
10377                        goal: SelectionGoal::None,
10378                    }
10379                })
10380                .collect();
10381
10382            this.change_selections(Default::default(), window, cx, |s| {
10383                s.select(new_selections);
10384            });
10385        });
10386    }
10387
10388    pub fn join_lines_impl(
10389        &mut self,
10390        insert_whitespace: bool,
10391        window: &mut Window,
10392        cx: &mut Context<Self>,
10393    ) {
10394        if self.read_only(cx) {
10395            return;
10396        }
10397        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10398        for selection in self.selections.all::<Point>(cx) {
10399            let start = MultiBufferRow(selection.start.row);
10400            // Treat single line selections as if they include the next line. Otherwise this action
10401            // would do nothing for single line selections individual cursors.
10402            let end = if selection.start.row == selection.end.row {
10403                MultiBufferRow(selection.start.row + 1)
10404            } else {
10405                MultiBufferRow(selection.end.row)
10406            };
10407
10408            if let Some(last_row_range) = row_ranges.last_mut()
10409                && start <= last_row_range.end
10410            {
10411                last_row_range.end = end;
10412                continue;
10413            }
10414            row_ranges.push(start..end);
10415        }
10416
10417        let snapshot = self.buffer.read(cx).snapshot(cx);
10418        let mut cursor_positions = Vec::new();
10419        for row_range in &row_ranges {
10420            let anchor = snapshot.anchor_before(Point::new(
10421                row_range.end.previous_row().0,
10422                snapshot.line_len(row_range.end.previous_row()),
10423            ));
10424            cursor_positions.push(anchor..anchor);
10425        }
10426
10427        self.transact(window, cx, |this, window, cx| {
10428            for row_range in row_ranges.into_iter().rev() {
10429                for row in row_range.iter_rows().rev() {
10430                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10431                    let next_line_row = row.next_row();
10432                    let indent = snapshot.indent_size_for_line(next_line_row);
10433                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10434
10435                    let replace =
10436                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10437                            " "
10438                        } else {
10439                            ""
10440                        };
10441
10442                    this.buffer.update(cx, |buffer, cx| {
10443                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10444                    });
10445                }
10446            }
10447
10448            this.change_selections(Default::default(), window, cx, |s| {
10449                s.select_anchor_ranges(cursor_positions)
10450            });
10451        });
10452    }
10453
10454    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10456        self.join_lines_impl(true, window, cx);
10457    }
10458
10459    pub fn sort_lines_case_sensitive(
10460        &mut self,
10461        _: &SortLinesCaseSensitive,
10462        window: &mut Window,
10463        cx: &mut Context<Self>,
10464    ) {
10465        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10466    }
10467
10468    pub fn sort_lines_by_length(
10469        &mut self,
10470        _: &SortLinesByLength,
10471        window: &mut Window,
10472        cx: &mut Context<Self>,
10473    ) {
10474        self.manipulate_immutable_lines(window, cx, |lines| {
10475            lines.sort_by_key(|&line| line.chars().count())
10476        })
10477    }
10478
10479    pub fn sort_lines_case_insensitive(
10480        &mut self,
10481        _: &SortLinesCaseInsensitive,
10482        window: &mut Window,
10483        cx: &mut Context<Self>,
10484    ) {
10485        self.manipulate_immutable_lines(window, cx, |lines| {
10486            lines.sort_by_key(|line| line.to_lowercase())
10487        })
10488    }
10489
10490    pub fn unique_lines_case_insensitive(
10491        &mut self,
10492        _: &UniqueLinesCaseInsensitive,
10493        window: &mut Window,
10494        cx: &mut Context<Self>,
10495    ) {
10496        self.manipulate_immutable_lines(window, cx, |lines| {
10497            let mut seen = HashSet::default();
10498            lines.retain(|line| seen.insert(line.to_lowercase()));
10499        })
10500    }
10501
10502    pub fn unique_lines_case_sensitive(
10503        &mut self,
10504        _: &UniqueLinesCaseSensitive,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) {
10508        self.manipulate_immutable_lines(window, cx, |lines| {
10509            let mut seen = HashSet::default();
10510            lines.retain(|line| seen.insert(*line));
10511        })
10512    }
10513
10514    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10515        let snapshot = self.buffer.read(cx).snapshot(cx);
10516        for selection in self.selections.disjoint_anchors().iter() {
10517            if snapshot
10518                .language_at(selection.start)
10519                .and_then(|lang| lang.config().wrap_characters.as_ref())
10520                .is_some()
10521            {
10522                return true;
10523            }
10524        }
10525        false
10526    }
10527
10528    fn wrap_selections_in_tag(
10529        &mut self,
10530        _: &WrapSelectionsInTag,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10535
10536        let snapshot = self.buffer.read(cx).snapshot(cx);
10537
10538        let mut edits = Vec::new();
10539        let mut boundaries = Vec::new();
10540
10541        for selection in self.selections.all::<Point>(cx).iter() {
10542            let Some(wrap_config) = snapshot
10543                .language_at(selection.start)
10544                .and_then(|lang| lang.config().wrap_characters.clone())
10545            else {
10546                continue;
10547            };
10548
10549            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10550            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10551
10552            let start_before = snapshot.anchor_before(selection.start);
10553            let end_after = snapshot.anchor_after(selection.end);
10554
10555            edits.push((start_before..start_before, open_tag));
10556            edits.push((end_after..end_after, close_tag));
10557
10558            boundaries.push((
10559                start_before,
10560                end_after,
10561                wrap_config.start_prefix.len(),
10562                wrap_config.end_suffix.len(),
10563            ));
10564        }
10565
10566        if edits.is_empty() {
10567            return;
10568        }
10569
10570        self.transact(window, cx, |this, window, cx| {
10571            let buffer = this.buffer.update(cx, |buffer, cx| {
10572                buffer.edit(edits, None, cx);
10573                buffer.snapshot(cx)
10574            });
10575
10576            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10577            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10578                boundaries.into_iter()
10579            {
10580                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10581                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10582                new_selections.push(open_offset..open_offset);
10583                new_selections.push(close_offset..close_offset);
10584            }
10585
10586            this.change_selections(Default::default(), window, cx, |s| {
10587                s.select_ranges(new_selections);
10588            });
10589
10590            this.request_autoscroll(Autoscroll::fit(), cx);
10591        });
10592    }
10593
10594    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10595        let Some(project) = self.project.clone() else {
10596            return;
10597        };
10598        self.reload(project, window, cx)
10599            .detach_and_notify_err(window, cx);
10600    }
10601
10602    pub fn restore_file(
10603        &mut self,
10604        _: &::git::RestoreFile,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10609        let mut buffer_ids = HashSet::default();
10610        let snapshot = self.buffer().read(cx).snapshot(cx);
10611        for selection in self.selections.all::<usize>(cx) {
10612            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10613        }
10614
10615        let buffer = self.buffer().read(cx);
10616        let ranges = buffer_ids
10617            .into_iter()
10618            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10619            .collect::<Vec<_>>();
10620
10621        self.restore_hunks_in_ranges(ranges, window, cx);
10622    }
10623
10624    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10625        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10626        let selections = self
10627            .selections
10628            .all(cx)
10629            .into_iter()
10630            .map(|s| s.range())
10631            .collect();
10632        self.restore_hunks_in_ranges(selections, window, cx);
10633    }
10634
10635    pub fn restore_hunks_in_ranges(
10636        &mut self,
10637        ranges: Vec<Range<Point>>,
10638        window: &mut Window,
10639        cx: &mut Context<Editor>,
10640    ) {
10641        let mut revert_changes = HashMap::default();
10642        let chunk_by = self
10643            .snapshot(window, cx)
10644            .hunks_for_ranges(ranges)
10645            .into_iter()
10646            .chunk_by(|hunk| hunk.buffer_id);
10647        for (buffer_id, hunks) in &chunk_by {
10648            let hunks = hunks.collect::<Vec<_>>();
10649            for hunk in &hunks {
10650                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10651            }
10652            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10653        }
10654        drop(chunk_by);
10655        if !revert_changes.is_empty() {
10656            self.transact(window, cx, |editor, window, cx| {
10657                editor.restore(revert_changes, window, cx);
10658            });
10659        }
10660    }
10661
10662    pub fn open_active_item_in_terminal(
10663        &mut self,
10664        _: &OpenInTerminal,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10669            let project_path = buffer.read(cx).project_path(cx)?;
10670            let project = self.project()?.read(cx);
10671            let entry = project.entry_for_path(&project_path, cx)?;
10672            let parent = match &entry.canonical_path {
10673                Some(canonical_path) => canonical_path.to_path_buf(),
10674                None => project.absolute_path(&project_path, cx)?,
10675            }
10676            .parent()?
10677            .to_path_buf();
10678            Some(parent)
10679        }) {
10680            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10681        }
10682    }
10683
10684    fn set_breakpoint_context_menu(
10685        &mut self,
10686        display_row: DisplayRow,
10687        position: Option<Anchor>,
10688        clicked_point: gpui::Point<Pixels>,
10689        window: &mut Window,
10690        cx: &mut Context<Self>,
10691    ) {
10692        let source = self
10693            .buffer
10694            .read(cx)
10695            .snapshot(cx)
10696            .anchor_before(Point::new(display_row.0, 0u32));
10697
10698        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10699
10700        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10701            self,
10702            source,
10703            clicked_point,
10704            context_menu,
10705            window,
10706            cx,
10707        );
10708    }
10709
10710    fn add_edit_breakpoint_block(
10711        &mut self,
10712        anchor: Anchor,
10713        breakpoint: &Breakpoint,
10714        edit_action: BreakpointPromptEditAction,
10715        window: &mut Window,
10716        cx: &mut Context<Self>,
10717    ) {
10718        let weak_editor = cx.weak_entity();
10719        let bp_prompt = cx.new(|cx| {
10720            BreakpointPromptEditor::new(
10721                weak_editor,
10722                anchor,
10723                breakpoint.clone(),
10724                edit_action,
10725                window,
10726                cx,
10727            )
10728        });
10729
10730        let height = bp_prompt.update(cx, |this, cx| {
10731            this.prompt
10732                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10733        });
10734        let cloned_prompt = bp_prompt.clone();
10735        let blocks = vec![BlockProperties {
10736            style: BlockStyle::Sticky,
10737            placement: BlockPlacement::Above(anchor),
10738            height: Some(height),
10739            render: Arc::new(move |cx| {
10740                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10741                cloned_prompt.clone().into_any_element()
10742            }),
10743            priority: 0,
10744        }];
10745
10746        let focus_handle = bp_prompt.focus_handle(cx);
10747        window.focus(&focus_handle);
10748
10749        let block_ids = self.insert_blocks(blocks, None, cx);
10750        bp_prompt.update(cx, |prompt, _| {
10751            prompt.add_block_ids(block_ids);
10752        });
10753    }
10754
10755    pub(crate) fn breakpoint_at_row(
10756        &self,
10757        row: u32,
10758        window: &mut Window,
10759        cx: &mut Context<Self>,
10760    ) -> Option<(Anchor, Breakpoint)> {
10761        let snapshot = self.snapshot(window, cx);
10762        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10763
10764        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10765    }
10766
10767    pub(crate) fn breakpoint_at_anchor(
10768        &self,
10769        breakpoint_position: Anchor,
10770        snapshot: &EditorSnapshot,
10771        cx: &mut Context<Self>,
10772    ) -> Option<(Anchor, Breakpoint)> {
10773        let buffer = self
10774            .buffer
10775            .read(cx)
10776            .buffer_for_anchor(breakpoint_position, cx)?;
10777
10778        let enclosing_excerpt = breakpoint_position.excerpt_id;
10779        let buffer_snapshot = buffer.read(cx).snapshot();
10780
10781        let row = buffer_snapshot
10782            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10783            .row;
10784
10785        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10786        let anchor_end = snapshot
10787            .buffer_snapshot
10788            .anchor_after(Point::new(row, line_len));
10789
10790        self.breakpoint_store
10791            .as_ref()?
10792            .read_with(cx, |breakpoint_store, cx| {
10793                breakpoint_store
10794                    .breakpoints(
10795                        &buffer,
10796                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10797                        &buffer_snapshot,
10798                        cx,
10799                    )
10800                    .next()
10801                    .and_then(|(bp, _)| {
10802                        let breakpoint_row = buffer_snapshot
10803                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10804                            .row;
10805
10806                        if breakpoint_row == row {
10807                            snapshot
10808                                .buffer_snapshot
10809                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10810                                .map(|position| (position, bp.bp.clone()))
10811                        } else {
10812                            None
10813                        }
10814                    })
10815            })
10816    }
10817
10818    pub fn edit_log_breakpoint(
10819        &mut self,
10820        _: &EditLogBreakpoint,
10821        window: &mut Window,
10822        cx: &mut Context<Self>,
10823    ) {
10824        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10825            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10826                message: None,
10827                state: BreakpointState::Enabled,
10828                condition: None,
10829                hit_condition: None,
10830            });
10831
10832            self.add_edit_breakpoint_block(
10833                anchor,
10834                &breakpoint,
10835                BreakpointPromptEditAction::Log,
10836                window,
10837                cx,
10838            );
10839        }
10840    }
10841
10842    fn breakpoints_at_cursors(
10843        &self,
10844        window: &mut Window,
10845        cx: &mut Context<Self>,
10846    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10847        let snapshot = self.snapshot(window, cx);
10848        let cursors = self
10849            .selections
10850            .disjoint_anchors()
10851            .iter()
10852            .map(|selection| {
10853                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10854
10855                let breakpoint_position = self
10856                    .breakpoint_at_row(cursor_position.row, window, cx)
10857                    .map(|bp| bp.0)
10858                    .unwrap_or_else(|| {
10859                        snapshot
10860                            .display_snapshot
10861                            .buffer_snapshot
10862                            .anchor_after(Point::new(cursor_position.row, 0))
10863                    });
10864
10865                let breakpoint = self
10866                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10867                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10868
10869                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10870            })
10871            // 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.
10872            .collect::<HashMap<Anchor, _>>();
10873
10874        cursors.into_iter().collect()
10875    }
10876
10877    pub fn enable_breakpoint(
10878        &mut self,
10879        _: &crate::actions::EnableBreakpoint,
10880        window: &mut Window,
10881        cx: &mut Context<Self>,
10882    ) {
10883        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10884            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10885                continue;
10886            };
10887            self.edit_breakpoint_at_anchor(
10888                anchor,
10889                breakpoint,
10890                BreakpointEditAction::InvertState,
10891                cx,
10892            );
10893        }
10894    }
10895
10896    pub fn disable_breakpoint(
10897        &mut self,
10898        _: &crate::actions::DisableBreakpoint,
10899        window: &mut Window,
10900        cx: &mut Context<Self>,
10901    ) {
10902        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10903            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10904                continue;
10905            };
10906            self.edit_breakpoint_at_anchor(
10907                anchor,
10908                breakpoint,
10909                BreakpointEditAction::InvertState,
10910                cx,
10911            );
10912        }
10913    }
10914
10915    pub fn toggle_breakpoint(
10916        &mut self,
10917        _: &crate::actions::ToggleBreakpoint,
10918        window: &mut Window,
10919        cx: &mut Context<Self>,
10920    ) {
10921        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10922            if let Some(breakpoint) = breakpoint {
10923                self.edit_breakpoint_at_anchor(
10924                    anchor,
10925                    breakpoint,
10926                    BreakpointEditAction::Toggle,
10927                    cx,
10928                );
10929            } else {
10930                self.edit_breakpoint_at_anchor(
10931                    anchor,
10932                    Breakpoint::new_standard(),
10933                    BreakpointEditAction::Toggle,
10934                    cx,
10935                );
10936            }
10937        }
10938    }
10939
10940    pub fn edit_breakpoint_at_anchor(
10941        &mut self,
10942        breakpoint_position: Anchor,
10943        breakpoint: Breakpoint,
10944        edit_action: BreakpointEditAction,
10945        cx: &mut Context<Self>,
10946    ) {
10947        let Some(breakpoint_store) = &self.breakpoint_store else {
10948            return;
10949        };
10950
10951        let Some(buffer) = self
10952            .buffer
10953            .read(cx)
10954            .buffer_for_anchor(breakpoint_position, cx)
10955        else {
10956            return;
10957        };
10958
10959        breakpoint_store.update(cx, |breakpoint_store, cx| {
10960            breakpoint_store.toggle_breakpoint(
10961                buffer,
10962                BreakpointWithPosition {
10963                    position: breakpoint_position.text_anchor,
10964                    bp: breakpoint,
10965                },
10966                edit_action,
10967                cx,
10968            );
10969        });
10970
10971        cx.notify();
10972    }
10973
10974    #[cfg(any(test, feature = "test-support"))]
10975    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10976        self.breakpoint_store.clone()
10977    }
10978
10979    pub fn prepare_restore_change(
10980        &self,
10981        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10982        hunk: &MultiBufferDiffHunk,
10983        cx: &mut App,
10984    ) -> Option<()> {
10985        if hunk.is_created_file() {
10986            return None;
10987        }
10988        let buffer = self.buffer.read(cx);
10989        let diff = buffer.diff_for(hunk.buffer_id)?;
10990        let buffer = buffer.buffer(hunk.buffer_id)?;
10991        let buffer = buffer.read(cx);
10992        let original_text = diff
10993            .read(cx)
10994            .base_text()
10995            .as_rope()
10996            .slice(hunk.diff_base_byte_range.clone());
10997        let buffer_snapshot = buffer.snapshot();
10998        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10999        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11000            probe
11001                .0
11002                .start
11003                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11004                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11005        }) {
11006            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11007            Some(())
11008        } else {
11009            None
11010        }
11011    }
11012
11013    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11014        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11015    }
11016
11017    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11018        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11019    }
11020
11021    fn manipulate_lines<M>(
11022        &mut self,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025        mut manipulate: M,
11026    ) where
11027        M: FnMut(&str) -> LineManipulationResult,
11028    {
11029        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11030
11031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11032        let buffer = self.buffer.read(cx).snapshot(cx);
11033
11034        let mut edits = Vec::new();
11035
11036        let selections = self.selections.all::<Point>(cx);
11037        let mut selections = selections.iter().peekable();
11038        let mut contiguous_row_selections = Vec::new();
11039        let mut new_selections = Vec::new();
11040        let mut added_lines = 0;
11041        let mut removed_lines = 0;
11042
11043        while let Some(selection) = selections.next() {
11044            let (start_row, end_row) = consume_contiguous_rows(
11045                &mut contiguous_row_selections,
11046                selection,
11047                &display_map,
11048                &mut selections,
11049            );
11050
11051            let start_point = Point::new(start_row.0, 0);
11052            let end_point = Point::new(
11053                end_row.previous_row().0,
11054                buffer.line_len(end_row.previous_row()),
11055            );
11056            let text = buffer
11057                .text_for_range(start_point..end_point)
11058                .collect::<String>();
11059
11060            let LineManipulationResult {
11061                new_text,
11062                line_count_before,
11063                line_count_after,
11064            } = manipulate(&text);
11065
11066            edits.push((start_point..end_point, new_text));
11067
11068            // Selections must change based on added and removed line count
11069            let start_row =
11070                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11071            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11072            new_selections.push(Selection {
11073                id: selection.id,
11074                start: start_row,
11075                end: end_row,
11076                goal: SelectionGoal::None,
11077                reversed: selection.reversed,
11078            });
11079
11080            if line_count_after > line_count_before {
11081                added_lines += line_count_after - line_count_before;
11082            } else if line_count_before > line_count_after {
11083                removed_lines += line_count_before - line_count_after;
11084            }
11085        }
11086
11087        self.transact(window, cx, |this, window, cx| {
11088            let buffer = this.buffer.update(cx, |buffer, cx| {
11089                buffer.edit(edits, None, cx);
11090                buffer.snapshot(cx)
11091            });
11092
11093            // Recalculate offsets on newly edited buffer
11094            let new_selections = new_selections
11095                .iter()
11096                .map(|s| {
11097                    let start_point = Point::new(s.start.0, 0);
11098                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11099                    Selection {
11100                        id: s.id,
11101                        start: buffer.point_to_offset(start_point),
11102                        end: buffer.point_to_offset(end_point),
11103                        goal: s.goal,
11104                        reversed: s.reversed,
11105                    }
11106                })
11107                .collect();
11108
11109            this.change_selections(Default::default(), window, cx, |s| {
11110                s.select(new_selections);
11111            });
11112
11113            this.request_autoscroll(Autoscroll::fit(), cx);
11114        });
11115    }
11116
11117    fn manipulate_immutable_lines<Fn>(
11118        &mut self,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121        mut callback: Fn,
11122    ) where
11123        Fn: FnMut(&mut Vec<&str>),
11124    {
11125        self.manipulate_lines(window, cx, |text| {
11126            let mut lines: Vec<&str> = text.split('\n').collect();
11127            let line_count_before = lines.len();
11128
11129            callback(&mut lines);
11130
11131            LineManipulationResult {
11132                new_text: lines.join("\n"),
11133                line_count_before,
11134                line_count_after: lines.len(),
11135            }
11136        });
11137    }
11138
11139    fn manipulate_mutable_lines<Fn>(
11140        &mut self,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143        mut callback: Fn,
11144    ) where
11145        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11146    {
11147        self.manipulate_lines(window, cx, |text| {
11148            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11149            let line_count_before = lines.len();
11150
11151            callback(&mut lines);
11152
11153            LineManipulationResult {
11154                new_text: lines.join("\n"),
11155                line_count_before,
11156                line_count_after: lines.len(),
11157            }
11158        });
11159    }
11160
11161    pub fn convert_indentation_to_spaces(
11162        &mut self,
11163        _: &ConvertIndentationToSpaces,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        let settings = self.buffer.read(cx).language_settings(cx);
11168        let tab_size = settings.tab_size.get() as usize;
11169
11170        self.manipulate_mutable_lines(window, cx, |lines| {
11171            // Allocates a reasonably sized scratch buffer once for the whole loop
11172            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11173            // Avoids recomputing spaces that could be inserted many times
11174            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11175                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11176                .collect();
11177
11178            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11179                let mut chars = line.as_ref().chars();
11180                let mut col = 0;
11181                let mut changed = false;
11182
11183                for ch in chars.by_ref() {
11184                    match ch {
11185                        ' ' => {
11186                            reindented_line.push(' ');
11187                            col += 1;
11188                        }
11189                        '\t' => {
11190                            // \t are converted to spaces depending on the current column
11191                            let spaces_len = tab_size - (col % tab_size);
11192                            reindented_line.extend(&space_cache[spaces_len - 1]);
11193                            col += spaces_len;
11194                            changed = true;
11195                        }
11196                        _ => {
11197                            // If we dont append before break, the character is consumed
11198                            reindented_line.push(ch);
11199                            break;
11200                        }
11201                    }
11202                }
11203
11204                if !changed {
11205                    reindented_line.clear();
11206                    continue;
11207                }
11208                // Append the rest of the line and replace old reference with new one
11209                reindented_line.extend(chars);
11210                *line = Cow::Owned(reindented_line.clone());
11211                reindented_line.clear();
11212            }
11213        });
11214    }
11215
11216    pub fn convert_indentation_to_tabs(
11217        &mut self,
11218        _: &ConvertIndentationToTabs,
11219        window: &mut Window,
11220        cx: &mut Context<Self>,
11221    ) {
11222        let settings = self.buffer.read(cx).language_settings(cx);
11223        let tab_size = settings.tab_size.get() as usize;
11224
11225        self.manipulate_mutable_lines(window, cx, |lines| {
11226            // Allocates a reasonably sized buffer once for the whole loop
11227            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11228            // Avoids recomputing spaces that could be inserted many times
11229            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11230                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11231                .collect();
11232
11233            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11234                let mut chars = line.chars();
11235                let mut spaces_count = 0;
11236                let mut first_non_indent_char = None;
11237                let mut changed = false;
11238
11239                for ch in chars.by_ref() {
11240                    match ch {
11241                        ' ' => {
11242                            // Keep track of spaces. Append \t when we reach tab_size
11243                            spaces_count += 1;
11244                            changed = true;
11245                            if spaces_count == tab_size {
11246                                reindented_line.push('\t');
11247                                spaces_count = 0;
11248                            }
11249                        }
11250                        '\t' => {
11251                            reindented_line.push('\t');
11252                            spaces_count = 0;
11253                        }
11254                        _ => {
11255                            // Dont append it yet, we might have remaining spaces
11256                            first_non_indent_char = Some(ch);
11257                            break;
11258                        }
11259                    }
11260                }
11261
11262                if !changed {
11263                    reindented_line.clear();
11264                    continue;
11265                }
11266                // Remaining spaces that didn't make a full tab stop
11267                if spaces_count > 0 {
11268                    reindented_line.extend(&space_cache[spaces_count - 1]);
11269                }
11270                // If we consume an extra character that was not indentation, add it back
11271                if let Some(extra_char) = first_non_indent_char {
11272                    reindented_line.push(extra_char);
11273                }
11274                // Append the rest of the line and replace old reference with new one
11275                reindented_line.extend(chars);
11276                *line = Cow::Owned(reindented_line.clone());
11277                reindented_line.clear();
11278            }
11279        });
11280    }
11281
11282    pub fn convert_to_upper_case(
11283        &mut self,
11284        _: &ConvertToUpperCase,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287    ) {
11288        self.manipulate_text(window, cx, |text| text.to_uppercase())
11289    }
11290
11291    pub fn convert_to_lower_case(
11292        &mut self,
11293        _: &ConvertToLowerCase,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.manipulate_text(window, cx, |text| text.to_lowercase())
11298    }
11299
11300    pub fn convert_to_title_case(
11301        &mut self,
11302        _: &ConvertToTitleCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| {
11307            text.split('\n')
11308                .map(|line| line.to_case(Case::Title))
11309                .join("\n")
11310        })
11311    }
11312
11313    pub fn convert_to_snake_case(
11314        &mut self,
11315        _: &ConvertToSnakeCase,
11316        window: &mut Window,
11317        cx: &mut Context<Self>,
11318    ) {
11319        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11320    }
11321
11322    pub fn convert_to_kebab_case(
11323        &mut self,
11324        _: &ConvertToKebabCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11329    }
11330
11331    pub fn convert_to_upper_camel_case(
11332        &mut self,
11333        _: &ConvertToUpperCamelCase,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        self.manipulate_text(window, cx, |text| {
11338            text.split('\n')
11339                .map(|line| line.to_case(Case::UpperCamel))
11340                .join("\n")
11341        })
11342    }
11343
11344    pub fn convert_to_lower_camel_case(
11345        &mut self,
11346        _: &ConvertToLowerCamelCase,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11351    }
11352
11353    pub fn convert_to_opposite_case(
11354        &mut self,
11355        _: &ConvertToOppositeCase,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.manipulate_text(window, cx, |text| {
11360            text.chars()
11361                .fold(String::with_capacity(text.len()), |mut t, c| {
11362                    if c.is_uppercase() {
11363                        t.extend(c.to_lowercase());
11364                    } else {
11365                        t.extend(c.to_uppercase());
11366                    }
11367                    t
11368                })
11369        })
11370    }
11371
11372    pub fn convert_to_sentence_case(
11373        &mut self,
11374        _: &ConvertToSentenceCase,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11379    }
11380
11381    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11382        self.manipulate_text(window, cx, |text| {
11383            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11384            if has_upper_case_characters {
11385                text.to_lowercase()
11386            } else {
11387                text.to_uppercase()
11388            }
11389        })
11390    }
11391
11392    pub fn convert_to_rot13(
11393        &mut self,
11394        _: &ConvertToRot13,
11395        window: &mut Window,
11396        cx: &mut Context<Self>,
11397    ) {
11398        self.manipulate_text(window, cx, |text| {
11399            text.chars()
11400                .map(|c| match c {
11401                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11402                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11403                    _ => c,
11404                })
11405                .collect()
11406        })
11407    }
11408
11409    pub fn convert_to_rot47(
11410        &mut self,
11411        _: &ConvertToRot47,
11412        window: &mut Window,
11413        cx: &mut Context<Self>,
11414    ) {
11415        self.manipulate_text(window, cx, |text| {
11416            text.chars()
11417                .map(|c| {
11418                    let code_point = c as u32;
11419                    if code_point >= 33 && code_point <= 126 {
11420                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11421                    }
11422                    c
11423                })
11424                .collect()
11425        })
11426    }
11427
11428    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11429    where
11430        Fn: FnMut(&str) -> String,
11431    {
11432        let buffer = self.buffer.read(cx).snapshot(cx);
11433
11434        let mut new_selections = Vec::new();
11435        let mut edits = Vec::new();
11436        let mut selection_adjustment = 0i32;
11437
11438        for selection in self.selections.all_adjusted(cx) {
11439            let selection_is_empty = selection.is_empty();
11440
11441            let (start, end) = if selection_is_empty {
11442                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11443                (word_range.start, word_range.end)
11444            } else {
11445                (
11446                    buffer.point_to_offset(selection.start),
11447                    buffer.point_to_offset(selection.end),
11448                )
11449            };
11450
11451            let text = buffer.text_for_range(start..end).collect::<String>();
11452            let old_length = text.len() as i32;
11453            let text = callback(&text);
11454
11455            new_selections.push(Selection {
11456                start: (start as i32 - selection_adjustment) as usize,
11457                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11458                goal: SelectionGoal::None,
11459                id: selection.id,
11460                reversed: selection.reversed,
11461            });
11462
11463            selection_adjustment += old_length - text.len() as i32;
11464
11465            edits.push((start..end, text));
11466        }
11467
11468        self.transact(window, cx, |this, window, cx| {
11469            this.buffer.update(cx, |buffer, cx| {
11470                buffer.edit(edits, None, cx);
11471            });
11472
11473            this.change_selections(Default::default(), window, cx, |s| {
11474                s.select(new_selections);
11475            });
11476
11477            this.request_autoscroll(Autoscroll::fit(), cx);
11478        });
11479    }
11480
11481    pub fn move_selection_on_drop(
11482        &mut self,
11483        selection: &Selection<Anchor>,
11484        target: DisplayPoint,
11485        is_cut: bool,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11490        let buffer = &display_map.buffer_snapshot;
11491        let mut edits = Vec::new();
11492        let insert_point = display_map
11493            .clip_point(target, Bias::Left)
11494            .to_point(&display_map);
11495        let text = buffer
11496            .text_for_range(selection.start..selection.end)
11497            .collect::<String>();
11498        if is_cut {
11499            edits.push(((selection.start..selection.end), String::new()));
11500        }
11501        let insert_anchor = buffer.anchor_before(insert_point);
11502        edits.push(((insert_anchor..insert_anchor), text));
11503        let last_edit_start = insert_anchor.bias_left(buffer);
11504        let last_edit_end = insert_anchor.bias_right(buffer);
11505        self.transact(window, cx, |this, window, cx| {
11506            this.buffer.update(cx, |buffer, cx| {
11507                buffer.edit(edits, None, cx);
11508            });
11509            this.change_selections(Default::default(), window, cx, |s| {
11510                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11511            });
11512        });
11513    }
11514
11515    pub fn clear_selection_drag_state(&mut self) {
11516        self.selection_drag_state = SelectionDragState::None;
11517    }
11518
11519    pub fn duplicate(
11520        &mut self,
11521        upwards: bool,
11522        whole_lines: bool,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11527
11528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11529        let buffer = &display_map.buffer_snapshot;
11530        let selections = self.selections.all::<Point>(cx);
11531
11532        let mut edits = Vec::new();
11533        let mut selections_iter = selections.iter().peekable();
11534        while let Some(selection) = selections_iter.next() {
11535            let mut rows = selection.spanned_rows(false, &display_map);
11536            // duplicate line-wise
11537            if whole_lines || selection.start == selection.end {
11538                // Avoid duplicating the same lines twice.
11539                while let Some(next_selection) = selections_iter.peek() {
11540                    let next_rows = next_selection.spanned_rows(false, &display_map);
11541                    if next_rows.start < rows.end {
11542                        rows.end = next_rows.end;
11543                        selections_iter.next().unwrap();
11544                    } else {
11545                        break;
11546                    }
11547                }
11548
11549                // Copy the text from the selected row region and splice it either at the start
11550                // or end of the region.
11551                let start = Point::new(rows.start.0, 0);
11552                let end = Point::new(
11553                    rows.end.previous_row().0,
11554                    buffer.line_len(rows.end.previous_row()),
11555                );
11556                let text = buffer
11557                    .text_for_range(start..end)
11558                    .chain(Some("\n"))
11559                    .collect::<String>();
11560                let insert_location = if upwards {
11561                    Point::new(rows.end.0, 0)
11562                } else {
11563                    start
11564                };
11565                edits.push((insert_location..insert_location, text));
11566            } else {
11567                // duplicate character-wise
11568                let start = selection.start;
11569                let end = selection.end;
11570                let text = buffer.text_for_range(start..end).collect::<String>();
11571                edits.push((selection.end..selection.end, text));
11572            }
11573        }
11574
11575        self.transact(window, cx, |this, _, cx| {
11576            this.buffer.update(cx, |buffer, cx| {
11577                buffer.edit(edits, None, cx);
11578            });
11579
11580            this.request_autoscroll(Autoscroll::fit(), cx);
11581        });
11582    }
11583
11584    pub fn duplicate_line_up(
11585        &mut self,
11586        _: &DuplicateLineUp,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589    ) {
11590        self.duplicate(true, true, window, cx);
11591    }
11592
11593    pub fn duplicate_line_down(
11594        &mut self,
11595        _: &DuplicateLineDown,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.duplicate(false, true, window, cx);
11600    }
11601
11602    pub fn duplicate_selection(
11603        &mut self,
11604        _: &DuplicateSelection,
11605        window: &mut Window,
11606        cx: &mut Context<Self>,
11607    ) {
11608        self.duplicate(false, false, window, cx);
11609    }
11610
11611    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11612        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11613        if self.mode.is_single_line() {
11614            cx.propagate();
11615            return;
11616        }
11617
11618        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11619        let buffer = self.buffer.read(cx).snapshot(cx);
11620
11621        let mut edits = Vec::new();
11622        let mut unfold_ranges = Vec::new();
11623        let mut refold_creases = Vec::new();
11624
11625        let selections = self.selections.all::<Point>(cx);
11626        let mut selections = selections.iter().peekable();
11627        let mut contiguous_row_selections = Vec::new();
11628        let mut new_selections = Vec::new();
11629
11630        while let Some(selection) = selections.next() {
11631            // Find all the selections that span a contiguous row range
11632            let (start_row, end_row) = consume_contiguous_rows(
11633                &mut contiguous_row_selections,
11634                selection,
11635                &display_map,
11636                &mut selections,
11637            );
11638
11639            // Move the text spanned by the row range to be before the line preceding the row range
11640            if start_row.0 > 0 {
11641                let range_to_move = Point::new(
11642                    start_row.previous_row().0,
11643                    buffer.line_len(start_row.previous_row()),
11644                )
11645                    ..Point::new(
11646                        end_row.previous_row().0,
11647                        buffer.line_len(end_row.previous_row()),
11648                    );
11649                let insertion_point = display_map
11650                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11651                    .0;
11652
11653                // Don't move lines across excerpts
11654                if buffer
11655                    .excerpt_containing(insertion_point..range_to_move.end)
11656                    .is_some()
11657                {
11658                    let text = buffer
11659                        .text_for_range(range_to_move.clone())
11660                        .flat_map(|s| s.chars())
11661                        .skip(1)
11662                        .chain(['\n'])
11663                        .collect::<String>();
11664
11665                    edits.push((
11666                        buffer.anchor_after(range_to_move.start)
11667                            ..buffer.anchor_before(range_to_move.end),
11668                        String::new(),
11669                    ));
11670                    let insertion_anchor = buffer.anchor_after(insertion_point);
11671                    edits.push((insertion_anchor..insertion_anchor, text));
11672
11673                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11674
11675                    // Move selections up
11676                    new_selections.extend(contiguous_row_selections.drain(..).map(
11677                        |mut selection| {
11678                            selection.start.row -= row_delta;
11679                            selection.end.row -= row_delta;
11680                            selection
11681                        },
11682                    ));
11683
11684                    // Move folds up
11685                    unfold_ranges.push(range_to_move.clone());
11686                    for fold in display_map.folds_in_range(
11687                        buffer.anchor_before(range_to_move.start)
11688                            ..buffer.anchor_after(range_to_move.end),
11689                    ) {
11690                        let mut start = fold.range.start.to_point(&buffer);
11691                        let mut end = fold.range.end.to_point(&buffer);
11692                        start.row -= row_delta;
11693                        end.row -= row_delta;
11694                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11695                    }
11696                }
11697            }
11698
11699            // If we didn't move line(s), preserve the existing selections
11700            new_selections.append(&mut contiguous_row_selections);
11701        }
11702
11703        self.transact(window, cx, |this, window, cx| {
11704            this.unfold_ranges(&unfold_ranges, true, true, cx);
11705            this.buffer.update(cx, |buffer, cx| {
11706                for (range, text) in edits {
11707                    buffer.edit([(range, text)], None, cx);
11708                }
11709            });
11710            this.fold_creases(refold_creases, true, window, cx);
11711            this.change_selections(Default::default(), window, cx, |s| {
11712                s.select(new_selections);
11713            })
11714        });
11715    }
11716
11717    pub fn move_line_down(
11718        &mut self,
11719        _: &MoveLineDown,
11720        window: &mut Window,
11721        cx: &mut Context<Self>,
11722    ) {
11723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11724        if self.mode.is_single_line() {
11725            cx.propagate();
11726            return;
11727        }
11728
11729        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11730        let buffer = self.buffer.read(cx).snapshot(cx);
11731
11732        let mut edits = Vec::new();
11733        let mut unfold_ranges = Vec::new();
11734        let mut refold_creases = Vec::new();
11735
11736        let selections = self.selections.all::<Point>(cx);
11737        let mut selections = selections.iter().peekable();
11738        let mut contiguous_row_selections = Vec::new();
11739        let mut new_selections = Vec::new();
11740
11741        while let Some(selection) = selections.next() {
11742            // Find all the selections that span a contiguous row range
11743            let (start_row, end_row) = consume_contiguous_rows(
11744                &mut contiguous_row_selections,
11745                selection,
11746                &display_map,
11747                &mut selections,
11748            );
11749
11750            // Move the text spanned by the row range to be after the last line of the row range
11751            if end_row.0 <= buffer.max_point().row {
11752                let range_to_move =
11753                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11754                let insertion_point = display_map
11755                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11756                    .0;
11757
11758                // Don't move lines across excerpt boundaries
11759                if buffer
11760                    .excerpt_containing(range_to_move.start..insertion_point)
11761                    .is_some()
11762                {
11763                    let mut text = String::from("\n");
11764                    text.extend(buffer.text_for_range(range_to_move.clone()));
11765                    text.pop(); // Drop trailing newline
11766                    edits.push((
11767                        buffer.anchor_after(range_to_move.start)
11768                            ..buffer.anchor_before(range_to_move.end),
11769                        String::new(),
11770                    ));
11771                    let insertion_anchor = buffer.anchor_after(insertion_point);
11772                    edits.push((insertion_anchor..insertion_anchor, text));
11773
11774                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11775
11776                    // Move selections down
11777                    new_selections.extend(contiguous_row_selections.drain(..).map(
11778                        |mut selection| {
11779                            selection.start.row += row_delta;
11780                            selection.end.row += row_delta;
11781                            selection
11782                        },
11783                    ));
11784
11785                    // Move folds down
11786                    unfold_ranges.push(range_to_move.clone());
11787                    for fold in display_map.folds_in_range(
11788                        buffer.anchor_before(range_to_move.start)
11789                            ..buffer.anchor_after(range_to_move.end),
11790                    ) {
11791                        let mut start = fold.range.start.to_point(&buffer);
11792                        let mut end = fold.range.end.to_point(&buffer);
11793                        start.row += row_delta;
11794                        end.row += row_delta;
11795                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11796                    }
11797                }
11798            }
11799
11800            // If we didn't move line(s), preserve the existing selections
11801            new_selections.append(&mut contiguous_row_selections);
11802        }
11803
11804        self.transact(window, cx, |this, window, cx| {
11805            this.unfold_ranges(&unfold_ranges, true, true, cx);
11806            this.buffer.update(cx, |buffer, cx| {
11807                for (range, text) in edits {
11808                    buffer.edit([(range, text)], None, cx);
11809                }
11810            });
11811            this.fold_creases(refold_creases, true, window, cx);
11812            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11813        });
11814    }
11815
11816    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11818        let text_layout_details = &self.text_layout_details(window);
11819        self.transact(window, cx, |this, window, cx| {
11820            let edits = this.change_selections(Default::default(), window, cx, |s| {
11821                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11822                s.move_with(|display_map, selection| {
11823                    if !selection.is_empty() {
11824                        return;
11825                    }
11826
11827                    let mut head = selection.head();
11828                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11829                    if head.column() == display_map.line_len(head.row()) {
11830                        transpose_offset = display_map
11831                            .buffer_snapshot
11832                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11833                    }
11834
11835                    if transpose_offset == 0 {
11836                        return;
11837                    }
11838
11839                    *head.column_mut() += 1;
11840                    head = display_map.clip_point(head, Bias::Right);
11841                    let goal = SelectionGoal::HorizontalPosition(
11842                        display_map
11843                            .x_for_display_point(head, text_layout_details)
11844                            .into(),
11845                    );
11846                    selection.collapse_to(head, goal);
11847
11848                    let transpose_start = display_map
11849                        .buffer_snapshot
11850                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11851                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11852                        let transpose_end = display_map
11853                            .buffer_snapshot
11854                            .clip_offset(transpose_offset + 1, Bias::Right);
11855                        if let Some(ch) =
11856                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11857                        {
11858                            edits.push((transpose_start..transpose_offset, String::new()));
11859                            edits.push((transpose_end..transpose_end, ch.to_string()));
11860                        }
11861                    }
11862                });
11863                edits
11864            });
11865            this.buffer
11866                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11867            let selections = this.selections.all::<usize>(cx);
11868            this.change_selections(Default::default(), window, cx, |s| {
11869                s.select(selections);
11870            });
11871        });
11872    }
11873
11874    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11875        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11876        if self.mode.is_single_line() {
11877            cx.propagate();
11878            return;
11879        }
11880
11881        self.rewrap_impl(RewrapOptions::default(), cx)
11882    }
11883
11884    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11885        let buffer = self.buffer.read(cx).snapshot(cx);
11886        let selections = self.selections.all::<Point>(cx);
11887
11888        #[derive(Clone, Debug, PartialEq)]
11889        enum CommentFormat {
11890            /// single line comment, with prefix for line
11891            Line(String),
11892            /// single line within a block comment, with prefix for line
11893            BlockLine(String),
11894            /// a single line of a block comment that includes the initial delimiter
11895            BlockCommentWithStart(BlockCommentConfig),
11896            /// a single line of a block comment that includes the ending delimiter
11897            BlockCommentWithEnd(BlockCommentConfig),
11898        }
11899
11900        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11901        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11902            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11903                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11904                .peekable();
11905
11906            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11907                row
11908            } else {
11909                return Vec::new();
11910            };
11911
11912            let language_settings = buffer.language_settings_at(selection.head(), cx);
11913            let language_scope = buffer.language_scope_at(selection.head());
11914
11915            let indent_and_prefix_for_row =
11916                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11917                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11918                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11919                        &language_scope
11920                    {
11921                        let indent_end = Point::new(row, indent.len);
11922                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11923                        let line_text_after_indent = buffer
11924                            .text_for_range(indent_end..line_end)
11925                            .collect::<String>();
11926
11927                        let is_within_comment_override = buffer
11928                            .language_scope_at(indent_end)
11929                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11930                        let comment_delimiters = if is_within_comment_override {
11931                            // we are within a comment syntax node, but we don't
11932                            // yet know what kind of comment: block, doc or line
11933                            match (
11934                                language_scope.documentation_comment(),
11935                                language_scope.block_comment(),
11936                            ) {
11937                                (Some(config), _) | (_, Some(config))
11938                                    if buffer.contains_str_at(indent_end, &config.start) =>
11939                                {
11940                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11941                                }
11942                                (Some(config), _) | (_, Some(config))
11943                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11944                                {
11945                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11946                                }
11947                                (Some(config), _) | (_, Some(config))
11948                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11949                                {
11950                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11951                                }
11952                                (_, _) => language_scope
11953                                    .line_comment_prefixes()
11954                                    .iter()
11955                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11956                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11957                            }
11958                        } else {
11959                            // we not in an overridden comment node, but we may
11960                            // be within a non-overridden line comment node
11961                            language_scope
11962                                .line_comment_prefixes()
11963                                .iter()
11964                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11965                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11966                        };
11967
11968                        let rewrap_prefix = language_scope
11969                            .rewrap_prefixes()
11970                            .iter()
11971                            .find_map(|prefix_regex| {
11972                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11973                                    if mat.start() == 0 {
11974                                        Some(mat.as_str().to_string())
11975                                    } else {
11976                                        None
11977                                    }
11978                                })
11979                            })
11980                            .flatten();
11981                        (comment_delimiters, rewrap_prefix)
11982                    } else {
11983                        (None, None)
11984                    };
11985                    (indent, comment_prefix, rewrap_prefix)
11986                };
11987
11988            let mut ranges = Vec::new();
11989            let from_empty_selection = selection.is_empty();
11990
11991            let mut current_range_start = first_row;
11992            let mut prev_row = first_row;
11993            let (
11994                mut current_range_indent,
11995                mut current_range_comment_delimiters,
11996                mut current_range_rewrap_prefix,
11997            ) = indent_and_prefix_for_row(first_row);
11998
11999            for row in non_blank_rows_iter.skip(1) {
12000                let has_paragraph_break = row > prev_row + 1;
12001
12002                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12003                    indent_and_prefix_for_row(row);
12004
12005                let has_indent_change = row_indent != current_range_indent;
12006                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12007
12008                let has_boundary_change = has_comment_change
12009                    || row_rewrap_prefix.is_some()
12010                    || (has_indent_change && current_range_comment_delimiters.is_some());
12011
12012                if has_paragraph_break || has_boundary_change {
12013                    ranges.push((
12014                        language_settings.clone(),
12015                        Point::new(current_range_start, 0)
12016                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12017                        current_range_indent,
12018                        current_range_comment_delimiters.clone(),
12019                        current_range_rewrap_prefix.clone(),
12020                        from_empty_selection,
12021                    ));
12022                    current_range_start = row;
12023                    current_range_indent = row_indent;
12024                    current_range_comment_delimiters = row_comment_delimiters;
12025                    current_range_rewrap_prefix = row_rewrap_prefix;
12026                }
12027                prev_row = row;
12028            }
12029
12030            ranges.push((
12031                language_settings.clone(),
12032                Point::new(current_range_start, 0)
12033                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12034                current_range_indent,
12035                current_range_comment_delimiters,
12036                current_range_rewrap_prefix,
12037                from_empty_selection,
12038            ));
12039
12040            ranges
12041        });
12042
12043        let mut edits = Vec::new();
12044        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12045
12046        for (
12047            language_settings,
12048            wrap_range,
12049            mut indent_size,
12050            comment_prefix,
12051            rewrap_prefix,
12052            from_empty_selection,
12053        ) in wrap_ranges
12054        {
12055            let mut start_row = wrap_range.start.row;
12056            let mut end_row = wrap_range.end.row;
12057
12058            // Skip selections that overlap with a range that has already been rewrapped.
12059            let selection_range = start_row..end_row;
12060            if rewrapped_row_ranges
12061                .iter()
12062                .any(|range| range.overlaps(&selection_range))
12063            {
12064                continue;
12065            }
12066
12067            let tab_size = language_settings.tab_size;
12068
12069            let (line_prefix, inside_comment) = match &comment_prefix {
12070                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12071                    (Some(prefix.as_str()), true)
12072                }
12073                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12074                    (Some(prefix.as_ref()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12077                    start: _,
12078                    end: _,
12079                    prefix,
12080                    tab_size,
12081                })) => {
12082                    indent_size.len += tab_size;
12083                    (Some(prefix.as_ref()), true)
12084                }
12085                None => (None, false),
12086            };
12087            let indent_prefix = indent_size.chars().collect::<String>();
12088            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12089
12090            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12091                RewrapBehavior::InComments => inside_comment,
12092                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12093                RewrapBehavior::Anywhere => true,
12094            };
12095
12096            let should_rewrap = options.override_language_settings
12097                || allow_rewrap_based_on_language
12098                || self.hard_wrap.is_some();
12099            if !should_rewrap {
12100                continue;
12101            }
12102
12103            if from_empty_selection {
12104                'expand_upwards: while start_row > 0 {
12105                    let prev_row = start_row - 1;
12106                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12107                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12108                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12109                    {
12110                        start_row = prev_row;
12111                    } else {
12112                        break 'expand_upwards;
12113                    }
12114                }
12115
12116                'expand_downwards: while end_row < buffer.max_point().row {
12117                    let next_row = end_row + 1;
12118                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12119                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12120                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12121                    {
12122                        end_row = next_row;
12123                    } else {
12124                        break 'expand_downwards;
12125                    }
12126                }
12127            }
12128
12129            let start = Point::new(start_row, 0);
12130            let start_offset = start.to_offset(&buffer);
12131            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12132            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12133            let mut first_line_delimiter = None;
12134            let mut last_line_delimiter = None;
12135            let Some(lines_without_prefixes) = selection_text
12136                .lines()
12137                .enumerate()
12138                .map(|(ix, line)| {
12139                    let line_trimmed = line.trim_start();
12140                    if rewrap_prefix.is_some() && ix > 0 {
12141                        Ok(line_trimmed)
12142                    } else if let Some(
12143                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12144                            start,
12145                            prefix,
12146                            end,
12147                            tab_size,
12148                        })
12149                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12150                            start,
12151                            prefix,
12152                            end,
12153                            tab_size,
12154                        }),
12155                    ) = &comment_prefix
12156                    {
12157                        let line_trimmed = line_trimmed
12158                            .strip_prefix(start.as_ref())
12159                            .map(|s| {
12160                                let mut indent_size = indent_size;
12161                                indent_size.len -= tab_size;
12162                                let indent_prefix: String = indent_size.chars().collect();
12163                                first_line_delimiter = Some((indent_prefix, start));
12164                                s.trim_start()
12165                            })
12166                            .unwrap_or(line_trimmed);
12167                        let line_trimmed = line_trimmed
12168                            .strip_suffix(end.as_ref())
12169                            .map(|s| {
12170                                last_line_delimiter = Some(end);
12171                                s.trim_end()
12172                            })
12173                            .unwrap_or(line_trimmed);
12174                        let line_trimmed = line_trimmed
12175                            .strip_prefix(prefix.as_ref())
12176                            .unwrap_or(line_trimmed);
12177                        Ok(line_trimmed)
12178                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12179                        line_trimmed.strip_prefix(prefix).with_context(|| {
12180                            format!("line did not start with prefix {prefix:?}: {line:?}")
12181                        })
12182                    } else {
12183                        line_trimmed
12184                            .strip_prefix(&line_prefix.trim_start())
12185                            .with_context(|| {
12186                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12187                            })
12188                    }
12189                })
12190                .collect::<Result<Vec<_>, _>>()
12191                .log_err()
12192            else {
12193                continue;
12194            };
12195
12196            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12197                buffer
12198                    .language_settings_at(Point::new(start_row, 0), cx)
12199                    .preferred_line_length as usize
12200            });
12201
12202            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12203                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12204            } else {
12205                line_prefix.clone()
12206            };
12207
12208            let wrapped_text = {
12209                let mut wrapped_text = wrap_with_prefix(
12210                    line_prefix,
12211                    subsequent_lines_prefix,
12212                    lines_without_prefixes.join("\n"),
12213                    wrap_column,
12214                    tab_size,
12215                    options.preserve_existing_whitespace,
12216                );
12217
12218                if let Some((indent, delimiter)) = first_line_delimiter {
12219                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12220                }
12221                if let Some(last_line) = last_line_delimiter {
12222                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12223                }
12224
12225                wrapped_text
12226            };
12227
12228            // TODO: should always use char-based diff while still supporting cursor behavior that
12229            // matches vim.
12230            let mut diff_options = DiffOptions::default();
12231            if options.override_language_settings {
12232                diff_options.max_word_diff_len = 0;
12233                diff_options.max_word_diff_line_count = 0;
12234            } else {
12235                diff_options.max_word_diff_len = usize::MAX;
12236                diff_options.max_word_diff_line_count = usize::MAX;
12237            }
12238
12239            for (old_range, new_text) in
12240                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12241            {
12242                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12243                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12244                edits.push((edit_start..edit_end, new_text));
12245            }
12246
12247            rewrapped_row_ranges.push(start_row..=end_row);
12248        }
12249
12250        self.buffer
12251            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12252    }
12253
12254    pub fn cut_common(
12255        &mut self,
12256        cut_no_selection_line: bool,
12257        window: &mut Window,
12258        cx: &mut Context<Self>,
12259    ) -> ClipboardItem {
12260        let mut text = String::new();
12261        let buffer = self.buffer.read(cx).snapshot(cx);
12262        let mut selections = self.selections.all::<Point>(cx);
12263        let mut clipboard_selections = Vec::with_capacity(selections.len());
12264        {
12265            let max_point = buffer.max_point();
12266            let mut is_first = true;
12267            for selection in &mut selections {
12268                let is_entire_line =
12269                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12270                if is_entire_line {
12271                    selection.start = Point::new(selection.start.row, 0);
12272                    if !selection.is_empty() && selection.end.column == 0 {
12273                        selection.end = cmp::min(max_point, selection.end);
12274                    } else {
12275                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12276                    }
12277                    selection.goal = SelectionGoal::None;
12278                }
12279                if is_first {
12280                    is_first = false;
12281                } else {
12282                    text += "\n";
12283                }
12284                let mut len = 0;
12285                for chunk in buffer.text_for_range(selection.start..selection.end) {
12286                    text.push_str(chunk);
12287                    len += chunk.len();
12288                }
12289                clipboard_selections.push(ClipboardSelection {
12290                    len,
12291                    is_entire_line,
12292                    first_line_indent: buffer
12293                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12294                        .len,
12295                });
12296            }
12297        }
12298
12299        self.transact(window, cx, |this, window, cx| {
12300            this.change_selections(Default::default(), window, cx, |s| {
12301                s.select(selections);
12302            });
12303            this.insert("", window, cx);
12304        });
12305        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12306    }
12307
12308    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12310        let item = self.cut_common(true, window, cx);
12311        cx.write_to_clipboard(item);
12312    }
12313
12314    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12316        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12317            s.move_with(|snapshot, sel| {
12318                if sel.is_empty() {
12319                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12320                }
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12323                }
12324            });
12325        });
12326        let item = self.cut_common(true, window, cx);
12327        cx.set_global(KillRing(item))
12328    }
12329
12330    pub fn kill_ring_yank(
12331        &mut self,
12332        _: &KillRingYank,
12333        window: &mut Window,
12334        cx: &mut Context<Self>,
12335    ) {
12336        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12337        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12338            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12339                (kill_ring.text().to_string(), kill_ring.metadata_json())
12340            } else {
12341                return;
12342            }
12343        } else {
12344            return;
12345        };
12346        self.do_paste(&text, metadata, false, window, cx);
12347    }
12348
12349    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12350        self.do_copy(true, cx);
12351    }
12352
12353    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12354        self.do_copy(false, cx);
12355    }
12356
12357    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12358        let selections = self.selections.all::<Point>(cx);
12359        let buffer = self.buffer.read(cx).read(cx);
12360        let mut text = String::new();
12361
12362        let mut clipboard_selections = Vec::with_capacity(selections.len());
12363        {
12364            let max_point = buffer.max_point();
12365            let mut is_first = true;
12366            for selection in &selections {
12367                let mut start = selection.start;
12368                let mut end = selection.end;
12369                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12370                if is_entire_line {
12371                    start = Point::new(start.row, 0);
12372                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12373                }
12374
12375                let mut trimmed_selections = Vec::new();
12376                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12377                    let row = MultiBufferRow(start.row);
12378                    let first_indent = buffer.indent_size_for_line(row);
12379                    if first_indent.len == 0 || start.column > first_indent.len {
12380                        trimmed_selections.push(start..end);
12381                    } else {
12382                        trimmed_selections.push(
12383                            Point::new(row.0, first_indent.len)
12384                                ..Point::new(row.0, buffer.line_len(row)),
12385                        );
12386                        for row in start.row + 1..=end.row {
12387                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12388                            if row == end.row {
12389                                line_len = end.column;
12390                            }
12391                            if line_len == 0 {
12392                                trimmed_selections
12393                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12394                                continue;
12395                            }
12396                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12397                            if row_indent_size.len >= first_indent.len {
12398                                trimmed_selections.push(
12399                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12400                                );
12401                            } else {
12402                                trimmed_selections.clear();
12403                                trimmed_selections.push(start..end);
12404                                break;
12405                            }
12406                        }
12407                    }
12408                } else {
12409                    trimmed_selections.push(start..end);
12410                }
12411
12412                for trimmed_range in trimmed_selections {
12413                    if is_first {
12414                        is_first = false;
12415                    } else {
12416                        text += "\n";
12417                    }
12418                    let mut len = 0;
12419                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12420                        text.push_str(chunk);
12421                        len += chunk.len();
12422                    }
12423                    clipboard_selections.push(ClipboardSelection {
12424                        len,
12425                        is_entire_line,
12426                        first_line_indent: buffer
12427                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12428                            .len,
12429                    });
12430                }
12431            }
12432        }
12433
12434        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12435            text,
12436            clipboard_selections,
12437        ));
12438    }
12439
12440    pub fn do_paste(
12441        &mut self,
12442        text: &String,
12443        clipboard_selections: Option<Vec<ClipboardSelection>>,
12444        handle_entire_lines: bool,
12445        window: &mut Window,
12446        cx: &mut Context<Self>,
12447    ) {
12448        if self.read_only(cx) {
12449            return;
12450        }
12451
12452        let clipboard_text = Cow::Borrowed(text);
12453
12454        self.transact(window, cx, |this, window, cx| {
12455            let had_active_edit_prediction = this.has_active_edit_prediction();
12456
12457            if let Some(mut clipboard_selections) = clipboard_selections {
12458                let old_selections = this.selections.all::<usize>(cx);
12459                let all_selections_were_entire_line =
12460                    clipboard_selections.iter().all(|s| s.is_entire_line);
12461                let first_selection_indent_column =
12462                    clipboard_selections.first().map(|s| s.first_line_indent);
12463                if clipboard_selections.len() != old_selections.len() {
12464                    clipboard_selections.drain(..);
12465                }
12466                let cursor_offset = this.selections.last::<usize>(cx).head();
12467                let mut auto_indent_on_paste = true;
12468
12469                this.buffer.update(cx, |buffer, cx| {
12470                    let snapshot = buffer.read(cx);
12471                    auto_indent_on_paste = snapshot
12472                        .language_settings_at(cursor_offset, cx)
12473                        .auto_indent_on_paste;
12474
12475                    let mut start_offset = 0;
12476                    let mut edits = Vec::new();
12477                    let mut original_indent_columns = Vec::new();
12478                    for (ix, selection) in old_selections.iter().enumerate() {
12479                        let to_insert;
12480                        let entire_line;
12481                        let original_indent_column;
12482                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12483                            let end_offset = start_offset + clipboard_selection.len;
12484                            to_insert = &clipboard_text[start_offset..end_offset];
12485                            entire_line = clipboard_selection.is_entire_line;
12486                            start_offset = end_offset + 1;
12487                            original_indent_column = Some(clipboard_selection.first_line_indent);
12488                        } else {
12489                            to_insert = clipboard_text.as_str();
12490                            entire_line = all_selections_were_entire_line;
12491                            original_indent_column = first_selection_indent_column
12492                        }
12493
12494                        // If the corresponding selection was empty when this slice of the
12495                        // clipboard text was written, then the entire line containing the
12496                        // selection was copied. If this selection is also currently empty,
12497                        // then paste the line before the current line of the buffer.
12498                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12499                            let column = selection.start.to_point(&snapshot).column as usize;
12500                            let line_start = selection.start - column;
12501                            line_start..line_start
12502                        } else {
12503                            selection.range()
12504                        };
12505
12506                        edits.push((range, to_insert));
12507                        original_indent_columns.push(original_indent_column);
12508                    }
12509                    drop(snapshot);
12510
12511                    buffer.edit(
12512                        edits,
12513                        if auto_indent_on_paste {
12514                            Some(AutoindentMode::Block {
12515                                original_indent_columns,
12516                            })
12517                        } else {
12518                            None
12519                        },
12520                        cx,
12521                    );
12522                });
12523
12524                let selections = this.selections.all::<usize>(cx);
12525                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12526            } else {
12527                this.insert(&clipboard_text, window, cx);
12528            }
12529
12530            let trigger_in_words =
12531                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12532
12533            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12534        });
12535    }
12536
12537    pub fn diff_clipboard_with_selection(
12538        &mut self,
12539        _: &DiffClipboardWithSelection,
12540        window: &mut Window,
12541        cx: &mut Context<Self>,
12542    ) {
12543        let selections = self.selections.all::<usize>(cx);
12544
12545        if selections.is_empty() {
12546            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12547            return;
12548        };
12549
12550        let clipboard_text = match cx.read_from_clipboard() {
12551            Some(item) => match item.entries().first() {
12552                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12553                _ => None,
12554            },
12555            None => None,
12556        };
12557
12558        let Some(clipboard_text) = clipboard_text else {
12559            log::warn!("Clipboard doesn't contain text.");
12560            return;
12561        };
12562
12563        window.dispatch_action(
12564            Box::new(DiffClipboardWithSelectionData {
12565                clipboard_text,
12566                editor: cx.entity(),
12567            }),
12568            cx,
12569        );
12570    }
12571
12572    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12574        if let Some(item) = cx.read_from_clipboard() {
12575            let entries = item.entries();
12576
12577            match entries.first() {
12578                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12579                // of all the pasted entries.
12580                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12581                    .do_paste(
12582                        clipboard_string.text(),
12583                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12584                        true,
12585                        window,
12586                        cx,
12587                    ),
12588                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12589            }
12590        }
12591    }
12592
12593    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12594        if self.read_only(cx) {
12595            return;
12596        }
12597
12598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12599
12600        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12601            if let Some((selections, _)) =
12602                self.selection_history.transaction(transaction_id).cloned()
12603            {
12604                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12605                    s.select_anchors(selections.to_vec());
12606                });
12607            } else {
12608                log::error!(
12609                    "No entry in selection_history found for undo. \
12610                     This may correspond to a bug where undo does not update the selection. \
12611                     If this is occurring, please add details to \
12612                     https://github.com/zed-industries/zed/issues/22692"
12613                );
12614            }
12615            self.request_autoscroll(Autoscroll::fit(), cx);
12616            self.unmark_text(window, cx);
12617            self.refresh_edit_prediction(true, false, window, cx);
12618            cx.emit(EditorEvent::Edited { transaction_id });
12619            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12620        }
12621    }
12622
12623    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12624        if self.read_only(cx) {
12625            return;
12626        }
12627
12628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12629
12630        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12631            if let Some((_, Some(selections))) =
12632                self.selection_history.transaction(transaction_id).cloned()
12633            {
12634                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12635                    s.select_anchors(selections.to_vec());
12636                });
12637            } else {
12638                log::error!(
12639                    "No entry in selection_history found for redo. \
12640                     This may correspond to a bug where undo does not update the selection. \
12641                     If this is occurring, please add details to \
12642                     https://github.com/zed-industries/zed/issues/22692"
12643                );
12644            }
12645            self.request_autoscroll(Autoscroll::fit(), cx);
12646            self.unmark_text(window, cx);
12647            self.refresh_edit_prediction(true, false, window, cx);
12648            cx.emit(EditorEvent::Edited { transaction_id });
12649        }
12650    }
12651
12652    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12653        self.buffer
12654            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12655    }
12656
12657    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12658        self.buffer
12659            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12660    }
12661
12662    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12664        self.change_selections(Default::default(), window, cx, |s| {
12665            s.move_with(|map, selection| {
12666                let cursor = if selection.is_empty() {
12667                    movement::left(map, selection.start)
12668                } else {
12669                    selection.start
12670                };
12671                selection.collapse_to(cursor, SelectionGoal::None);
12672            });
12673        })
12674    }
12675
12676    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12678        self.change_selections(Default::default(), window, cx, |s| {
12679            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12680        })
12681    }
12682
12683    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12685        self.change_selections(Default::default(), window, cx, |s| {
12686            s.move_with(|map, selection| {
12687                let cursor = if selection.is_empty() {
12688                    movement::right(map, selection.end)
12689                } else {
12690                    selection.end
12691                };
12692                selection.collapse_to(cursor, SelectionGoal::None)
12693            });
12694        })
12695    }
12696
12697    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12699        self.change_selections(Default::default(), window, cx, |s| {
12700            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12701        })
12702    }
12703
12704    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12705        if self.take_rename(true, window, cx).is_some() {
12706            return;
12707        }
12708
12709        if self.mode.is_single_line() {
12710            cx.propagate();
12711            return;
12712        }
12713
12714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12715
12716        let text_layout_details = &self.text_layout_details(window);
12717        let selection_count = self.selections.count();
12718        let first_selection = self.selections.first_anchor();
12719
12720        self.change_selections(Default::default(), window, cx, |s| {
12721            s.move_with(|map, selection| {
12722                if !selection.is_empty() {
12723                    selection.goal = SelectionGoal::None;
12724                }
12725                let (cursor, goal) = movement::up(
12726                    map,
12727                    selection.start,
12728                    selection.goal,
12729                    false,
12730                    text_layout_details,
12731                );
12732                selection.collapse_to(cursor, goal);
12733            });
12734        });
12735
12736        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12737        {
12738            cx.propagate();
12739        }
12740    }
12741
12742    pub fn move_up_by_lines(
12743        &mut self,
12744        action: &MoveUpByLines,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) {
12748        if self.take_rename(true, window, cx).is_some() {
12749            return;
12750        }
12751
12752        if self.mode.is_single_line() {
12753            cx.propagate();
12754            return;
12755        }
12756
12757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12758
12759        let text_layout_details = &self.text_layout_details(window);
12760
12761        self.change_selections(Default::default(), window, cx, |s| {
12762            s.move_with(|map, selection| {
12763                if !selection.is_empty() {
12764                    selection.goal = SelectionGoal::None;
12765                }
12766                let (cursor, goal) = movement::up_by_rows(
12767                    map,
12768                    selection.start,
12769                    action.lines,
12770                    selection.goal,
12771                    false,
12772                    text_layout_details,
12773                );
12774                selection.collapse_to(cursor, goal);
12775            });
12776        })
12777    }
12778
12779    pub fn move_down_by_lines(
12780        &mut self,
12781        action: &MoveDownByLines,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if self.take_rename(true, window, cx).is_some() {
12786            return;
12787        }
12788
12789        if self.mode.is_single_line() {
12790            cx.propagate();
12791            return;
12792        }
12793
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12795
12796        let text_layout_details = &self.text_layout_details(window);
12797
12798        self.change_selections(Default::default(), window, cx, |s| {
12799            s.move_with(|map, selection| {
12800                if !selection.is_empty() {
12801                    selection.goal = SelectionGoal::None;
12802                }
12803                let (cursor, goal) = movement::down_by_rows(
12804                    map,
12805                    selection.start,
12806                    action.lines,
12807                    selection.goal,
12808                    false,
12809                    text_layout_details,
12810                );
12811                selection.collapse_to(cursor, goal);
12812            });
12813        })
12814    }
12815
12816    pub fn select_down_by_lines(
12817        &mut self,
12818        action: &SelectDownByLines,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12823        let text_layout_details = &self.text_layout_details(window);
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_heads_with(|map, head, goal| {
12826                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12827            })
12828        })
12829    }
12830
12831    pub fn select_up_by_lines(
12832        &mut self,
12833        action: &SelectUpByLines,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12838        let text_layout_details = &self.text_layout_details(window);
12839        self.change_selections(Default::default(), window, cx, |s| {
12840            s.move_heads_with(|map, head, goal| {
12841                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12842            })
12843        })
12844    }
12845
12846    pub fn select_page_up(
12847        &mut self,
12848        _: &SelectPageUp,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        let Some(row_count) = self.visible_row_count() else {
12853            return;
12854        };
12855
12856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12857
12858        let text_layout_details = &self.text_layout_details(window);
12859
12860        self.change_selections(Default::default(), window, cx, |s| {
12861            s.move_heads_with(|map, head, goal| {
12862                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12863            })
12864        })
12865    }
12866
12867    pub fn move_page_up(
12868        &mut self,
12869        action: &MovePageUp,
12870        window: &mut Window,
12871        cx: &mut Context<Self>,
12872    ) {
12873        if self.take_rename(true, window, cx).is_some() {
12874            return;
12875        }
12876
12877        if self
12878            .context_menu
12879            .borrow_mut()
12880            .as_mut()
12881            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12882            .unwrap_or(false)
12883        {
12884            return;
12885        }
12886
12887        if matches!(self.mode, EditorMode::SingleLine) {
12888            cx.propagate();
12889            return;
12890        }
12891
12892        let Some(row_count) = self.visible_row_count() else {
12893            return;
12894        };
12895
12896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12897
12898        let effects = if action.center_cursor {
12899            SelectionEffects::scroll(Autoscroll::center())
12900        } else {
12901            SelectionEffects::default()
12902        };
12903
12904        let text_layout_details = &self.text_layout_details(window);
12905
12906        self.change_selections(effects, window, cx, |s| {
12907            s.move_with(|map, selection| {
12908                if !selection.is_empty() {
12909                    selection.goal = SelectionGoal::None;
12910                }
12911                let (cursor, goal) = movement::up_by_rows(
12912                    map,
12913                    selection.end,
12914                    row_count,
12915                    selection.goal,
12916                    false,
12917                    text_layout_details,
12918                );
12919                selection.collapse_to(cursor, goal);
12920            });
12921        });
12922    }
12923
12924    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        let text_layout_details = &self.text_layout_details(window);
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_heads_with(|map, head, goal| {
12929                movement::up(map, head, goal, false, text_layout_details)
12930            })
12931        })
12932    }
12933
12934    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12935        self.take_rename(true, window, cx);
12936
12937        if self.mode.is_single_line() {
12938            cx.propagate();
12939            return;
12940        }
12941
12942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12943
12944        let text_layout_details = &self.text_layout_details(window);
12945        let selection_count = self.selections.count();
12946        let first_selection = self.selections.first_anchor();
12947
12948        self.change_selections(Default::default(), window, cx, |s| {
12949            s.move_with(|map, selection| {
12950                if !selection.is_empty() {
12951                    selection.goal = SelectionGoal::None;
12952                }
12953                let (cursor, goal) = movement::down(
12954                    map,
12955                    selection.end,
12956                    selection.goal,
12957                    false,
12958                    text_layout_details,
12959                );
12960                selection.collapse_to(cursor, goal);
12961            });
12962        });
12963
12964        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12965        {
12966            cx.propagate();
12967        }
12968    }
12969
12970    pub fn select_page_down(
12971        &mut self,
12972        _: &SelectPageDown,
12973        window: &mut Window,
12974        cx: &mut Context<Self>,
12975    ) {
12976        let Some(row_count) = self.visible_row_count() else {
12977            return;
12978        };
12979
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12981
12982        let text_layout_details = &self.text_layout_details(window);
12983
12984        self.change_selections(Default::default(), window, cx, |s| {
12985            s.move_heads_with(|map, head, goal| {
12986                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12987            })
12988        })
12989    }
12990
12991    pub fn move_page_down(
12992        &mut self,
12993        action: &MovePageDown,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) {
12997        if self.take_rename(true, window, cx).is_some() {
12998            return;
12999        }
13000
13001        if self
13002            .context_menu
13003            .borrow_mut()
13004            .as_mut()
13005            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13006            .unwrap_or(false)
13007        {
13008            return;
13009        }
13010
13011        if matches!(self.mode, EditorMode::SingleLine) {
13012            cx.propagate();
13013            return;
13014        }
13015
13016        let Some(row_count) = self.visible_row_count() else {
13017            return;
13018        };
13019
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13021
13022        let effects = if action.center_cursor {
13023            SelectionEffects::scroll(Autoscroll::center())
13024        } else {
13025            SelectionEffects::default()
13026        };
13027
13028        let text_layout_details = &self.text_layout_details(window);
13029        self.change_selections(effects, window, cx, |s| {
13030            s.move_with(|map, selection| {
13031                if !selection.is_empty() {
13032                    selection.goal = SelectionGoal::None;
13033                }
13034                let (cursor, goal) = movement::down_by_rows(
13035                    map,
13036                    selection.end,
13037                    row_count,
13038                    selection.goal,
13039                    false,
13040                    text_layout_details,
13041                );
13042                selection.collapse_to(cursor, goal);
13043            });
13044        });
13045    }
13046
13047    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13049        let text_layout_details = &self.text_layout_details(window);
13050        self.change_selections(Default::default(), window, cx, |s| {
13051            s.move_heads_with(|map, head, goal| {
13052                movement::down(map, head, goal, false, text_layout_details)
13053            })
13054        });
13055    }
13056
13057    pub fn context_menu_first(
13058        &mut self,
13059        _: &ContextMenuFirst,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13064            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13065        }
13066    }
13067
13068    pub fn context_menu_prev(
13069        &mut self,
13070        _: &ContextMenuPrevious,
13071        window: &mut Window,
13072        cx: &mut Context<Self>,
13073    ) {
13074        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13075            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13076        }
13077    }
13078
13079    pub fn context_menu_next(
13080        &mut self,
13081        _: &ContextMenuNext,
13082        window: &mut Window,
13083        cx: &mut Context<Self>,
13084    ) {
13085        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13086            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13087        }
13088    }
13089
13090    pub fn context_menu_last(
13091        &mut self,
13092        _: &ContextMenuLast,
13093        window: &mut Window,
13094        cx: &mut Context<Self>,
13095    ) {
13096        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13097            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13098        }
13099    }
13100
13101    pub fn signature_help_prev(
13102        &mut self,
13103        _: &SignatureHelpPrevious,
13104        _: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        if let Some(popover) = self.signature_help_state.popover_mut() {
13108            if popover.current_signature == 0 {
13109                popover.current_signature = popover.signatures.len() - 1;
13110            } else {
13111                popover.current_signature -= 1;
13112            }
13113            cx.notify();
13114        }
13115    }
13116
13117    pub fn signature_help_next(
13118        &mut self,
13119        _: &SignatureHelpNext,
13120        _: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        if let Some(popover) = self.signature_help_state.popover_mut() {
13124            if popover.current_signature + 1 == popover.signatures.len() {
13125                popover.current_signature = 0;
13126            } else {
13127                popover.current_signature += 1;
13128            }
13129            cx.notify();
13130        }
13131    }
13132
13133    pub fn move_to_previous_word_start(
13134        &mut self,
13135        _: &MoveToPreviousWordStart,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140        self.change_selections(Default::default(), window, cx, |s| {
13141            s.move_cursors_with(|map, head, _| {
13142                (
13143                    movement::previous_word_start(map, head),
13144                    SelectionGoal::None,
13145                )
13146            });
13147        })
13148    }
13149
13150    pub fn move_to_previous_subword_start(
13151        &mut self,
13152        _: &MoveToPreviousSubwordStart,
13153        window: &mut Window,
13154        cx: &mut Context<Self>,
13155    ) {
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13157        self.change_selections(Default::default(), window, cx, |s| {
13158            s.move_cursors_with(|map, head, _| {
13159                (
13160                    movement::previous_subword_start(map, head),
13161                    SelectionGoal::None,
13162                )
13163            });
13164        })
13165    }
13166
13167    pub fn select_to_previous_word_start(
13168        &mut self,
13169        _: &SelectToPreviousWordStart,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13174        self.change_selections(Default::default(), window, cx, |s| {
13175            s.move_heads_with(|map, head, _| {
13176                (
13177                    movement::previous_word_start(map, head),
13178                    SelectionGoal::None,
13179                )
13180            });
13181        })
13182    }
13183
13184    pub fn select_to_previous_subword_start(
13185        &mut self,
13186        _: &SelectToPreviousSubwordStart,
13187        window: &mut Window,
13188        cx: &mut Context<Self>,
13189    ) {
13190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13191        self.change_selections(Default::default(), window, cx, |s| {
13192            s.move_heads_with(|map, head, _| {
13193                (
13194                    movement::previous_subword_start(map, head),
13195                    SelectionGoal::None,
13196                )
13197            });
13198        })
13199    }
13200
13201    pub fn delete_to_previous_word_start(
13202        &mut self,
13203        action: &DeleteToPreviousWordStart,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208        self.transact(window, cx, |this, window, cx| {
13209            this.select_autoclose_pair(window, cx);
13210            this.change_selections(Default::default(), window, cx, |s| {
13211                s.move_with(|map, selection| {
13212                    if selection.is_empty() {
13213                        let mut cursor = if action.ignore_newlines {
13214                            movement::previous_word_start(map, selection.head())
13215                        } else {
13216                            movement::previous_word_start_or_newline(map, selection.head())
13217                        };
13218                        cursor = movement::adjust_greedy_deletion(
13219                            map,
13220                            selection.head(),
13221                            cursor,
13222                            action.ignore_brackets,
13223                        );
13224                        selection.set_head(cursor, SelectionGoal::None);
13225                    }
13226                });
13227            });
13228            this.insert("", window, cx);
13229        });
13230    }
13231
13232    pub fn delete_to_previous_subword_start(
13233        &mut self,
13234        _: &DeleteToPreviousSubwordStart,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13239        self.transact(window, cx, |this, window, cx| {
13240            this.select_autoclose_pair(window, cx);
13241            this.change_selections(Default::default(), window, cx, |s| {
13242                s.move_with(|map, selection| {
13243                    if selection.is_empty() {
13244                        let mut cursor = movement::previous_subword_start(map, selection.head());
13245                        cursor =
13246                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13247                        selection.set_head(cursor, SelectionGoal::None);
13248                    }
13249                });
13250            });
13251            this.insert("", window, cx);
13252        });
13253    }
13254
13255    pub fn move_to_next_word_end(
13256        &mut self,
13257        _: &MoveToNextWordEnd,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13262        self.change_selections(Default::default(), window, cx, |s| {
13263            s.move_cursors_with(|map, head, _| {
13264                (movement::next_word_end(map, head), SelectionGoal::None)
13265            });
13266        })
13267    }
13268
13269    pub fn move_to_next_subword_end(
13270        &mut self,
13271        _: &MoveToNextSubwordEnd,
13272        window: &mut Window,
13273        cx: &mut Context<Self>,
13274    ) {
13275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13276        self.change_selections(Default::default(), window, cx, |s| {
13277            s.move_cursors_with(|map, head, _| {
13278                (movement::next_subword_end(map, head), SelectionGoal::None)
13279            });
13280        })
13281    }
13282
13283    pub fn select_to_next_word_end(
13284        &mut self,
13285        _: &SelectToNextWordEnd,
13286        window: &mut Window,
13287        cx: &mut Context<Self>,
13288    ) {
13289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13290        self.change_selections(Default::default(), window, cx, |s| {
13291            s.move_heads_with(|map, head, _| {
13292                (movement::next_word_end(map, head), SelectionGoal::None)
13293            });
13294        })
13295    }
13296
13297    pub fn select_to_next_subword_end(
13298        &mut self,
13299        _: &SelectToNextSubwordEnd,
13300        window: &mut Window,
13301        cx: &mut Context<Self>,
13302    ) {
13303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13304        self.change_selections(Default::default(), window, cx, |s| {
13305            s.move_heads_with(|map, head, _| {
13306                (movement::next_subword_end(map, head), SelectionGoal::None)
13307            });
13308        })
13309    }
13310
13311    pub fn delete_to_next_word_end(
13312        &mut self,
13313        action: &DeleteToNextWordEnd,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13318        self.transact(window, cx, |this, window, cx| {
13319            this.change_selections(Default::default(), window, cx, |s| {
13320                s.move_with(|map, selection| {
13321                    if selection.is_empty() {
13322                        let mut cursor = if action.ignore_newlines {
13323                            movement::next_word_end(map, selection.head())
13324                        } else {
13325                            movement::next_word_end_or_newline(map, selection.head())
13326                        };
13327                        cursor = movement::adjust_greedy_deletion(
13328                            map,
13329                            selection.head(),
13330                            cursor,
13331                            action.ignore_brackets,
13332                        );
13333                        selection.set_head(cursor, SelectionGoal::None);
13334                    }
13335                });
13336            });
13337            this.insert("", window, cx);
13338        });
13339    }
13340
13341    pub fn delete_to_next_subword_end(
13342        &mut self,
13343        _: &DeleteToNextSubwordEnd,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13348        self.transact(window, cx, |this, window, cx| {
13349            this.change_selections(Default::default(), window, cx, |s| {
13350                s.move_with(|map, selection| {
13351                    if selection.is_empty() {
13352                        let mut cursor = movement::next_subword_end(map, selection.head());
13353                        cursor =
13354                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13355                        selection.set_head(cursor, SelectionGoal::None);
13356                    }
13357                });
13358            });
13359            this.insert("", window, cx);
13360        });
13361    }
13362
13363    pub fn move_to_beginning_of_line(
13364        &mut self,
13365        action: &MoveToBeginningOfLine,
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_cursors_with(|map, head, _| {
13372                (
13373                    movement::indented_line_beginning(
13374                        map,
13375                        head,
13376                        action.stop_at_soft_wraps,
13377                        action.stop_at_indent,
13378                    ),
13379                    SelectionGoal::None,
13380                )
13381            });
13382        })
13383    }
13384
13385    pub fn select_to_beginning_of_line(
13386        &mut self,
13387        action: &SelectToBeginningOfLine,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13392        self.change_selections(Default::default(), window, cx, |s| {
13393            s.move_heads_with(|map, head, _| {
13394                (
13395                    movement::indented_line_beginning(
13396                        map,
13397                        head,
13398                        action.stop_at_soft_wraps,
13399                        action.stop_at_indent,
13400                    ),
13401                    SelectionGoal::None,
13402                )
13403            });
13404        });
13405    }
13406
13407    pub fn delete_to_beginning_of_line(
13408        &mut self,
13409        action: &DeleteToBeginningOfLine,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13414        self.transact(window, cx, |this, window, cx| {
13415            this.change_selections(Default::default(), window, cx, |s| {
13416                s.move_with(|_, selection| {
13417                    selection.reversed = true;
13418                });
13419            });
13420
13421            this.select_to_beginning_of_line(
13422                &SelectToBeginningOfLine {
13423                    stop_at_soft_wraps: false,
13424                    stop_at_indent: action.stop_at_indent,
13425                },
13426                window,
13427                cx,
13428            );
13429            this.backspace(&Backspace, window, cx);
13430        });
13431    }
13432
13433    pub fn move_to_end_of_line(
13434        &mut self,
13435        action: &MoveToEndOfLine,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) {
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13440        self.change_selections(Default::default(), window, cx, |s| {
13441            s.move_cursors_with(|map, head, _| {
13442                (
13443                    movement::line_end(map, head, action.stop_at_soft_wraps),
13444                    SelectionGoal::None,
13445                )
13446            });
13447        })
13448    }
13449
13450    pub fn select_to_end_of_line(
13451        &mut self,
13452        action: &SelectToEndOfLine,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13457        self.change_selections(Default::default(), window, cx, |s| {
13458            s.move_heads_with(|map, head, _| {
13459                (
13460                    movement::line_end(map, head, action.stop_at_soft_wraps),
13461                    SelectionGoal::None,
13462                )
13463            });
13464        })
13465    }
13466
13467    pub fn delete_to_end_of_line(
13468        &mut self,
13469        _: &DeleteToEndOfLine,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13474        self.transact(window, cx, |this, window, cx| {
13475            this.select_to_end_of_line(
13476                &SelectToEndOfLine {
13477                    stop_at_soft_wraps: false,
13478                },
13479                window,
13480                cx,
13481            );
13482            this.delete(&Delete, window, cx);
13483        });
13484    }
13485
13486    pub fn cut_to_end_of_line(
13487        &mut self,
13488        action: &CutToEndOfLine,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13493        self.transact(window, cx, |this, window, cx| {
13494            this.select_to_end_of_line(
13495                &SelectToEndOfLine {
13496                    stop_at_soft_wraps: false,
13497                },
13498                window,
13499                cx,
13500            );
13501            if !action.stop_at_newlines {
13502                this.change_selections(Default::default(), window, cx, |s| {
13503                    s.move_with(|_, sel| {
13504                        if sel.is_empty() {
13505                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13506                        }
13507                    });
13508                });
13509            }
13510            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13511            let item = this.cut_common(false, window, cx);
13512            cx.write_to_clipboard(item);
13513        });
13514    }
13515
13516    pub fn move_to_start_of_paragraph(
13517        &mut self,
13518        _: &MoveToStartOfParagraph,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if matches!(self.mode, EditorMode::SingleLine) {
13523            cx.propagate();
13524            return;
13525        }
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_with(|map, selection| {
13529                selection.collapse_to(
13530                    movement::start_of_paragraph(map, selection.head(), 1),
13531                    SelectionGoal::None,
13532                )
13533            });
13534        })
13535    }
13536
13537    pub fn move_to_end_of_paragraph(
13538        &mut self,
13539        _: &MoveToEndOfParagraph,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        if matches!(self.mode, EditorMode::SingleLine) {
13544            cx.propagate();
13545            return;
13546        }
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_with(|map, selection| {
13550                selection.collapse_to(
13551                    movement::end_of_paragraph(map, selection.head(), 1),
13552                    SelectionGoal::None,
13553                )
13554            });
13555        })
13556    }
13557
13558    pub fn select_to_start_of_paragraph(
13559        &mut self,
13560        _: &SelectToStartOfParagraph,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        if matches!(self.mode, EditorMode::SingleLine) {
13565            cx.propagate();
13566            return;
13567        }
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_heads_with(|map, head, _| {
13571                (
13572                    movement::start_of_paragraph(map, head, 1),
13573                    SelectionGoal::None,
13574                )
13575            });
13576        })
13577    }
13578
13579    pub fn select_to_end_of_paragraph(
13580        &mut self,
13581        _: &SelectToEndOfParagraph,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if matches!(self.mode, EditorMode::SingleLine) {
13586            cx.propagate();
13587            return;
13588        }
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_heads_with(|map, head, _| {
13592                (
13593                    movement::end_of_paragraph(map, head, 1),
13594                    SelectionGoal::None,
13595                )
13596            });
13597        })
13598    }
13599
13600    pub fn move_to_start_of_excerpt(
13601        &mut self,
13602        _: &MoveToStartOfExcerpt,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        if matches!(self.mode, EditorMode::SingleLine) {
13607            cx.propagate();
13608            return;
13609        }
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                selection.collapse_to(
13614                    movement::start_of_excerpt(
13615                        map,
13616                        selection.head(),
13617                        workspace::searchable::Direction::Prev,
13618                    ),
13619                    SelectionGoal::None,
13620                )
13621            });
13622        })
13623    }
13624
13625    pub fn move_to_start_of_next_excerpt(
13626        &mut self,
13627        _: &MoveToStartOfNextExcerpt,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        if matches!(self.mode, EditorMode::SingleLine) {
13632            cx.propagate();
13633            return;
13634        }
13635
13636        self.change_selections(Default::default(), window, cx, |s| {
13637            s.move_with(|map, selection| {
13638                selection.collapse_to(
13639                    movement::start_of_excerpt(
13640                        map,
13641                        selection.head(),
13642                        workspace::searchable::Direction::Next,
13643                    ),
13644                    SelectionGoal::None,
13645                )
13646            });
13647        })
13648    }
13649
13650    pub fn move_to_end_of_excerpt(
13651        &mut self,
13652        _: &MoveToEndOfExcerpt,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        if matches!(self.mode, EditorMode::SingleLine) {
13657            cx.propagate();
13658            return;
13659        }
13660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13661        self.change_selections(Default::default(), window, cx, |s| {
13662            s.move_with(|map, selection| {
13663                selection.collapse_to(
13664                    movement::end_of_excerpt(
13665                        map,
13666                        selection.head(),
13667                        workspace::searchable::Direction::Next,
13668                    ),
13669                    SelectionGoal::None,
13670                )
13671            });
13672        })
13673    }
13674
13675    pub fn move_to_end_of_previous_excerpt(
13676        &mut self,
13677        _: &MoveToEndOfPreviousExcerpt,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        if matches!(self.mode, EditorMode::SingleLine) {
13682            cx.propagate();
13683            return;
13684        }
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686        self.change_selections(Default::default(), window, cx, |s| {
13687            s.move_with(|map, selection| {
13688                selection.collapse_to(
13689                    movement::end_of_excerpt(
13690                        map,
13691                        selection.head(),
13692                        workspace::searchable::Direction::Prev,
13693                    ),
13694                    SelectionGoal::None,
13695                )
13696            });
13697        })
13698    }
13699
13700    pub fn select_to_start_of_excerpt(
13701        &mut self,
13702        _: &SelectToStartOfExcerpt,
13703        window: &mut Window,
13704        cx: &mut Context<Self>,
13705    ) {
13706        if matches!(self.mode, EditorMode::SingleLine) {
13707            cx.propagate();
13708            return;
13709        }
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_heads_with(|map, head, _| {
13713                (
13714                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13715                    SelectionGoal::None,
13716                )
13717            });
13718        })
13719    }
13720
13721    pub fn select_to_start_of_next_excerpt(
13722        &mut self,
13723        _: &SelectToStartOfNextExcerpt,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        if matches!(self.mode, EditorMode::SingleLine) {
13728            cx.propagate();
13729            return;
13730        }
13731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_heads_with(|map, head, _| {
13734                (
13735                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13736                    SelectionGoal::None,
13737                )
13738            });
13739        })
13740    }
13741
13742    pub fn select_to_end_of_excerpt(
13743        &mut self,
13744        _: &SelectToEndOfExcerpt,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if matches!(self.mode, EditorMode::SingleLine) {
13749            cx.propagate();
13750            return;
13751        }
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.move_heads_with(|map, head, _| {
13755                (
13756                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_end_of_previous_excerpt(
13764        &mut self,
13765        _: &SelectToEndOfPreviousExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn move_to_beginning(
13785        &mut self,
13786        _: &MoveToBeginning,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.select_ranges(vec![0..0]);
13797        });
13798    }
13799
13800    pub fn select_to_beginning(
13801        &mut self,
13802        _: &SelectToBeginning,
13803        window: &mut Window,
13804        cx: &mut Context<Self>,
13805    ) {
13806        let mut selection = self.selections.last::<Point>(cx);
13807        selection.set_head(Point::zero(), SelectionGoal::None);
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13809        self.change_selections(Default::default(), window, cx, |s| {
13810            s.select(vec![selection]);
13811        });
13812    }
13813
13814    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13815        if matches!(self.mode, EditorMode::SingleLine) {
13816            cx.propagate();
13817            return;
13818        }
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13820        let cursor = self.buffer.read(cx).read(cx).len();
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.select_ranges(vec![cursor..cursor])
13823        });
13824    }
13825
13826    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13827        self.nav_history = nav_history;
13828    }
13829
13830    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13831        self.nav_history.as_ref()
13832    }
13833
13834    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13835        self.push_to_nav_history(
13836            self.selections.newest_anchor().head(),
13837            None,
13838            false,
13839            true,
13840            cx,
13841        );
13842    }
13843
13844    fn push_to_nav_history(
13845        &mut self,
13846        cursor_anchor: Anchor,
13847        new_position: Option<Point>,
13848        is_deactivate: bool,
13849        always: bool,
13850        cx: &mut Context<Self>,
13851    ) {
13852        if let Some(nav_history) = self.nav_history.as_mut() {
13853            let buffer = self.buffer.read(cx).read(cx);
13854            let cursor_position = cursor_anchor.to_point(&buffer);
13855            let scroll_state = self.scroll_manager.anchor();
13856            let scroll_top_row = scroll_state.top_row(&buffer);
13857            drop(buffer);
13858
13859            if let Some(new_position) = new_position {
13860                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13861                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13862                    return;
13863                }
13864            }
13865
13866            nav_history.push(
13867                Some(NavigationData {
13868                    cursor_anchor,
13869                    cursor_position,
13870                    scroll_anchor: scroll_state,
13871                    scroll_top_row,
13872                }),
13873                cx,
13874            );
13875            cx.emit(EditorEvent::PushedToNavHistory {
13876                anchor: cursor_anchor,
13877                is_deactivate,
13878            })
13879        }
13880    }
13881
13882    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13884        let buffer = self.buffer.read(cx).snapshot(cx);
13885        let mut selection = self.selections.first::<usize>(cx);
13886        selection.set_head(buffer.len(), SelectionGoal::None);
13887        self.change_selections(Default::default(), window, cx, |s| {
13888            s.select(vec![selection]);
13889        });
13890    }
13891
13892    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        let end = self.buffer.read(cx).read(cx).len();
13895        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13896            s.select_ranges(vec![0..end]);
13897        });
13898    }
13899
13900    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13903        let mut selections = self.selections.all::<Point>(cx);
13904        let max_point = display_map.buffer_snapshot.max_point();
13905        for selection in &mut selections {
13906            let rows = selection.spanned_rows(true, &display_map);
13907            selection.start = Point::new(rows.start.0, 0);
13908            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13909            selection.reversed = false;
13910        }
13911        self.change_selections(Default::default(), window, cx, |s| {
13912            s.select(selections);
13913        });
13914    }
13915
13916    pub fn split_selection_into_lines(
13917        &mut self,
13918        action: &SplitSelectionIntoLines,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        let selections = self
13923            .selections
13924            .all::<Point>(cx)
13925            .into_iter()
13926            .map(|selection| selection.start..selection.end)
13927            .collect::<Vec<_>>();
13928        self.unfold_ranges(&selections, true, true, cx);
13929
13930        let mut new_selection_ranges = Vec::new();
13931        {
13932            let buffer = self.buffer.read(cx).read(cx);
13933            for selection in selections {
13934                for row in selection.start.row..selection.end.row {
13935                    let line_start = Point::new(row, 0);
13936                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13937
13938                    if action.keep_selections {
13939                        // Keep the selection range for each line
13940                        let selection_start = if row == selection.start.row {
13941                            selection.start
13942                        } else {
13943                            line_start
13944                        };
13945                        new_selection_ranges.push(selection_start..line_end);
13946                    } else {
13947                        // Collapse to cursor at end of line
13948                        new_selection_ranges.push(line_end..line_end);
13949                    }
13950                }
13951
13952                let is_multiline_selection = selection.start.row != selection.end.row;
13953                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13954                // so this action feels more ergonomic when paired with other selection operations
13955                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13956                if !should_skip_last {
13957                    if action.keep_selections {
13958                        if is_multiline_selection {
13959                            let line_start = Point::new(selection.end.row, 0);
13960                            new_selection_ranges.push(line_start..selection.end);
13961                        } else {
13962                            new_selection_ranges.push(selection.start..selection.end);
13963                        }
13964                    } else {
13965                        new_selection_ranges.push(selection.end..selection.end);
13966                    }
13967                }
13968            }
13969        }
13970        self.change_selections(Default::default(), window, cx, |s| {
13971            s.select_ranges(new_selection_ranges);
13972        });
13973    }
13974
13975    pub fn add_selection_above(
13976        &mut self,
13977        _: &AddSelectionAbove,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        self.add_selection(true, window, cx);
13982    }
13983
13984    pub fn add_selection_below(
13985        &mut self,
13986        _: &AddSelectionBelow,
13987        window: &mut Window,
13988        cx: &mut Context<Self>,
13989    ) {
13990        self.add_selection(false, window, cx);
13991    }
13992
13993    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13995
13996        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13997        let all_selections = self.selections.all::<Point>(cx);
13998        let text_layout_details = self.text_layout_details(window);
13999
14000        let (mut columnar_selections, new_selections_to_columnarize) = {
14001            if let Some(state) = self.add_selections_state.as_ref() {
14002                let columnar_selection_ids: HashSet<_> = state
14003                    .groups
14004                    .iter()
14005                    .flat_map(|group| group.stack.iter())
14006                    .copied()
14007                    .collect();
14008
14009                all_selections
14010                    .into_iter()
14011                    .partition(|s| columnar_selection_ids.contains(&s.id))
14012            } else {
14013                (Vec::new(), all_selections)
14014            }
14015        };
14016
14017        let mut state = self
14018            .add_selections_state
14019            .take()
14020            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14021
14022        for selection in new_selections_to_columnarize {
14023            let range = selection.display_range(&display_map).sorted();
14024            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14025            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14026            let positions = start_x.min(end_x)..start_x.max(end_x);
14027            let mut stack = Vec::new();
14028            for row in range.start.row().0..=range.end.row().0 {
14029                if let Some(selection) = self.selections.build_columnar_selection(
14030                    &display_map,
14031                    DisplayRow(row),
14032                    &positions,
14033                    selection.reversed,
14034                    &text_layout_details,
14035                ) {
14036                    stack.push(selection.id);
14037                    columnar_selections.push(selection);
14038                }
14039            }
14040            if !stack.is_empty() {
14041                if above {
14042                    stack.reverse();
14043                }
14044                state.groups.push(AddSelectionsGroup { above, stack });
14045            }
14046        }
14047
14048        let mut final_selections = Vec::new();
14049        let end_row = if above {
14050            DisplayRow(0)
14051        } else {
14052            display_map.max_point().row()
14053        };
14054
14055        let mut last_added_item_per_group = HashMap::default();
14056        for group in state.groups.iter_mut() {
14057            if let Some(last_id) = group.stack.last() {
14058                last_added_item_per_group.insert(*last_id, group);
14059            }
14060        }
14061
14062        for selection in columnar_selections {
14063            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14064                if above == group.above {
14065                    let range = selection.display_range(&display_map).sorted();
14066                    debug_assert_eq!(range.start.row(), range.end.row());
14067                    let mut row = range.start.row();
14068                    let positions =
14069                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14070                            px(start)..px(end)
14071                        } else {
14072                            let start_x =
14073                                display_map.x_for_display_point(range.start, &text_layout_details);
14074                            let end_x =
14075                                display_map.x_for_display_point(range.end, &text_layout_details);
14076                            start_x.min(end_x)..start_x.max(end_x)
14077                        };
14078
14079                    let mut maybe_new_selection = None;
14080                    while row != end_row {
14081                        if above {
14082                            row.0 -= 1;
14083                        } else {
14084                            row.0 += 1;
14085                        }
14086                        if let Some(new_selection) = self.selections.build_columnar_selection(
14087                            &display_map,
14088                            row,
14089                            &positions,
14090                            selection.reversed,
14091                            &text_layout_details,
14092                        ) {
14093                            maybe_new_selection = Some(new_selection);
14094                            break;
14095                        }
14096                    }
14097
14098                    if let Some(new_selection) = maybe_new_selection {
14099                        group.stack.push(new_selection.id);
14100                        if above {
14101                            final_selections.push(new_selection);
14102                            final_selections.push(selection);
14103                        } else {
14104                            final_selections.push(selection);
14105                            final_selections.push(new_selection);
14106                        }
14107                    } else {
14108                        final_selections.push(selection);
14109                    }
14110                } else {
14111                    group.stack.pop();
14112                }
14113            } else {
14114                final_selections.push(selection);
14115            }
14116        }
14117
14118        self.change_selections(Default::default(), window, cx, |s| {
14119            s.select(final_selections);
14120        });
14121
14122        let final_selection_ids: HashSet<_> = self
14123            .selections
14124            .all::<Point>(cx)
14125            .iter()
14126            .map(|s| s.id)
14127            .collect();
14128        state.groups.retain_mut(|group| {
14129            // selections might get merged above so we remove invalid items from stacks
14130            group.stack.retain(|id| final_selection_ids.contains(id));
14131
14132            // single selection in stack can be treated as initial state
14133            group.stack.len() > 1
14134        });
14135
14136        if !state.groups.is_empty() {
14137            self.add_selections_state = Some(state);
14138        }
14139    }
14140
14141    fn select_match_ranges(
14142        &mut self,
14143        range: Range<usize>,
14144        reversed: bool,
14145        replace_newest: bool,
14146        auto_scroll: Option<Autoscroll>,
14147        window: &mut Window,
14148        cx: &mut Context<Editor>,
14149    ) {
14150        self.unfold_ranges(
14151            std::slice::from_ref(&range),
14152            false,
14153            auto_scroll.is_some(),
14154            cx,
14155        );
14156        let effects = if let Some(scroll) = auto_scroll {
14157            SelectionEffects::scroll(scroll)
14158        } else {
14159            SelectionEffects::no_scroll()
14160        };
14161        self.change_selections(effects, window, cx, |s| {
14162            if replace_newest {
14163                s.delete(s.newest_anchor().id);
14164            }
14165            if reversed {
14166                s.insert_range(range.end..range.start);
14167            } else {
14168                s.insert_range(range);
14169            }
14170        });
14171    }
14172
14173    pub fn select_next_match_internal(
14174        &mut self,
14175        display_map: &DisplaySnapshot,
14176        replace_newest: bool,
14177        autoscroll: Option<Autoscroll>,
14178        window: &mut Window,
14179        cx: &mut Context<Self>,
14180    ) -> Result<()> {
14181        let buffer = &display_map.buffer_snapshot;
14182        let mut selections = self.selections.all::<usize>(cx);
14183        if let Some(mut select_next_state) = self.select_next_state.take() {
14184            let query = &select_next_state.query;
14185            if !select_next_state.done {
14186                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14187                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14188                let mut next_selected_range = None;
14189
14190                let bytes_after_last_selection =
14191                    buffer.bytes_in_range(last_selection.end..buffer.len());
14192                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14193                let query_matches = query
14194                    .stream_find_iter(bytes_after_last_selection)
14195                    .map(|result| (last_selection.end, result))
14196                    .chain(
14197                        query
14198                            .stream_find_iter(bytes_before_first_selection)
14199                            .map(|result| (0, result)),
14200                    );
14201
14202                for (start_offset, query_match) in query_matches {
14203                    let query_match = query_match.unwrap(); // can only fail due to I/O
14204                    let offset_range =
14205                        start_offset + query_match.start()..start_offset + query_match.end();
14206
14207                    if !select_next_state.wordwise
14208                        || (!buffer.is_inside_word(offset_range.start, false)
14209                            && !buffer.is_inside_word(offset_range.end, false))
14210                    {
14211                        // TODO: This is n^2, because we might check all the selections
14212                        if !selections
14213                            .iter()
14214                            .any(|selection| selection.range().overlaps(&offset_range))
14215                        {
14216                            next_selected_range = Some(offset_range);
14217                            break;
14218                        }
14219                    }
14220                }
14221
14222                if let Some(next_selected_range) = next_selected_range {
14223                    self.select_match_ranges(
14224                        next_selected_range,
14225                        last_selection.reversed,
14226                        replace_newest,
14227                        autoscroll,
14228                        window,
14229                        cx,
14230                    );
14231                } else {
14232                    select_next_state.done = true;
14233                }
14234            }
14235
14236            self.select_next_state = Some(select_next_state);
14237        } else {
14238            let mut only_carets = true;
14239            let mut same_text_selected = true;
14240            let mut selected_text = None;
14241
14242            let mut selections_iter = selections.iter().peekable();
14243            while let Some(selection) = selections_iter.next() {
14244                if selection.start != selection.end {
14245                    only_carets = false;
14246                }
14247
14248                if same_text_selected {
14249                    if selected_text.is_none() {
14250                        selected_text =
14251                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14252                    }
14253
14254                    if let Some(next_selection) = selections_iter.peek() {
14255                        if next_selection.range().len() == selection.range().len() {
14256                            let next_selected_text = buffer
14257                                .text_for_range(next_selection.range())
14258                                .collect::<String>();
14259                            if Some(next_selected_text) != selected_text {
14260                                same_text_selected = false;
14261                                selected_text = None;
14262                            }
14263                        } else {
14264                            same_text_selected = false;
14265                            selected_text = None;
14266                        }
14267                    }
14268                }
14269            }
14270
14271            if only_carets {
14272                for selection in &mut selections {
14273                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14274                    selection.start = word_range.start;
14275                    selection.end = word_range.end;
14276                    selection.goal = SelectionGoal::None;
14277                    selection.reversed = false;
14278                    self.select_match_ranges(
14279                        selection.start..selection.end,
14280                        selection.reversed,
14281                        replace_newest,
14282                        autoscroll,
14283                        window,
14284                        cx,
14285                    );
14286                }
14287
14288                if selections.len() == 1 {
14289                    let selection = selections
14290                        .last()
14291                        .expect("ensured that there's only one selection");
14292                    let query = buffer
14293                        .text_for_range(selection.start..selection.end)
14294                        .collect::<String>();
14295                    let is_empty = query.is_empty();
14296                    let select_state = SelectNextState {
14297                        query: AhoCorasick::new(&[query])?,
14298                        wordwise: true,
14299                        done: is_empty,
14300                    };
14301                    self.select_next_state = Some(select_state);
14302                } else {
14303                    self.select_next_state = None;
14304                }
14305            } else if let Some(selected_text) = selected_text {
14306                self.select_next_state = Some(SelectNextState {
14307                    query: AhoCorasick::new(&[selected_text])?,
14308                    wordwise: false,
14309                    done: false,
14310                });
14311                self.select_next_match_internal(
14312                    display_map,
14313                    replace_newest,
14314                    autoscroll,
14315                    window,
14316                    cx,
14317                )?;
14318            }
14319        }
14320        Ok(())
14321    }
14322
14323    pub fn select_all_matches(
14324        &mut self,
14325        _action: &SelectAllMatches,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) -> Result<()> {
14329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14330
14331        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14332
14333        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14334        let Some(select_next_state) = self.select_next_state.as_mut() else {
14335            return Ok(());
14336        };
14337        if select_next_state.done {
14338            return Ok(());
14339        }
14340
14341        let mut new_selections = Vec::new();
14342
14343        let reversed = self.selections.oldest::<usize>(cx).reversed;
14344        let buffer = &display_map.buffer_snapshot;
14345        let query_matches = select_next_state
14346            .query
14347            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14348
14349        for query_match in query_matches.into_iter() {
14350            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14351            let offset_range = if reversed {
14352                query_match.end()..query_match.start()
14353            } else {
14354                query_match.start()..query_match.end()
14355            };
14356
14357            if !select_next_state.wordwise
14358                || (!buffer.is_inside_word(offset_range.start, false)
14359                    && !buffer.is_inside_word(offset_range.end, false))
14360            {
14361                new_selections.push(offset_range.start..offset_range.end);
14362            }
14363        }
14364
14365        select_next_state.done = true;
14366
14367        if new_selections.is_empty() {
14368            log::error!("bug: new_selections is empty in select_all_matches");
14369            return Ok(());
14370        }
14371
14372        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14373        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14374            selections.select_ranges(new_selections)
14375        });
14376
14377        Ok(())
14378    }
14379
14380    pub fn select_next(
14381        &mut self,
14382        action: &SelectNext,
14383        window: &mut Window,
14384        cx: &mut Context<Self>,
14385    ) -> Result<()> {
14386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14387        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14388        self.select_next_match_internal(
14389            &display_map,
14390            action.replace_newest,
14391            Some(Autoscroll::newest()),
14392            window,
14393            cx,
14394        )?;
14395        Ok(())
14396    }
14397
14398    pub fn select_previous(
14399        &mut self,
14400        action: &SelectPrevious,
14401        window: &mut Window,
14402        cx: &mut Context<Self>,
14403    ) -> Result<()> {
14404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14406        let buffer = &display_map.buffer_snapshot;
14407        let mut selections = self.selections.all::<usize>(cx);
14408        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14409            let query = &select_prev_state.query;
14410            if !select_prev_state.done {
14411                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14412                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14413                let mut next_selected_range = None;
14414                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14415                let bytes_before_last_selection =
14416                    buffer.reversed_bytes_in_range(0..last_selection.start);
14417                let bytes_after_first_selection =
14418                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14419                let query_matches = query
14420                    .stream_find_iter(bytes_before_last_selection)
14421                    .map(|result| (last_selection.start, result))
14422                    .chain(
14423                        query
14424                            .stream_find_iter(bytes_after_first_selection)
14425                            .map(|result| (buffer.len(), result)),
14426                    );
14427                for (end_offset, query_match) in query_matches {
14428                    let query_match = query_match.unwrap(); // can only fail due to I/O
14429                    let offset_range =
14430                        end_offset - query_match.end()..end_offset - query_match.start();
14431
14432                    if !select_prev_state.wordwise
14433                        || (!buffer.is_inside_word(offset_range.start, false)
14434                            && !buffer.is_inside_word(offset_range.end, false))
14435                    {
14436                        next_selected_range = Some(offset_range);
14437                        break;
14438                    }
14439                }
14440
14441                if let Some(next_selected_range) = next_selected_range {
14442                    self.select_match_ranges(
14443                        next_selected_range,
14444                        last_selection.reversed,
14445                        action.replace_newest,
14446                        Some(Autoscroll::newest()),
14447                        window,
14448                        cx,
14449                    );
14450                } else {
14451                    select_prev_state.done = true;
14452                }
14453            }
14454
14455            self.select_prev_state = Some(select_prev_state);
14456        } else {
14457            let mut only_carets = true;
14458            let mut same_text_selected = true;
14459            let mut selected_text = None;
14460
14461            let mut selections_iter = selections.iter().peekable();
14462            while let Some(selection) = selections_iter.next() {
14463                if selection.start != selection.end {
14464                    only_carets = false;
14465                }
14466
14467                if same_text_selected {
14468                    if selected_text.is_none() {
14469                        selected_text =
14470                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14471                    }
14472
14473                    if let Some(next_selection) = selections_iter.peek() {
14474                        if next_selection.range().len() == selection.range().len() {
14475                            let next_selected_text = buffer
14476                                .text_for_range(next_selection.range())
14477                                .collect::<String>();
14478                            if Some(next_selected_text) != selected_text {
14479                                same_text_selected = false;
14480                                selected_text = None;
14481                            }
14482                        } else {
14483                            same_text_selected = false;
14484                            selected_text = None;
14485                        }
14486                    }
14487                }
14488            }
14489
14490            if only_carets {
14491                for selection in &mut selections {
14492                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14493                    selection.start = word_range.start;
14494                    selection.end = word_range.end;
14495                    selection.goal = SelectionGoal::None;
14496                    selection.reversed = false;
14497                    self.select_match_ranges(
14498                        selection.start..selection.end,
14499                        selection.reversed,
14500                        action.replace_newest,
14501                        Some(Autoscroll::newest()),
14502                        window,
14503                        cx,
14504                    );
14505                }
14506                if selections.len() == 1 {
14507                    let selection = selections
14508                        .last()
14509                        .expect("ensured that there's only one selection");
14510                    let query = buffer
14511                        .text_for_range(selection.start..selection.end)
14512                        .collect::<String>();
14513                    let is_empty = query.is_empty();
14514                    let select_state = SelectNextState {
14515                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14516                        wordwise: true,
14517                        done: is_empty,
14518                    };
14519                    self.select_prev_state = Some(select_state);
14520                } else {
14521                    self.select_prev_state = None;
14522                }
14523            } else if let Some(selected_text) = selected_text {
14524                self.select_prev_state = Some(SelectNextState {
14525                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14526                    wordwise: false,
14527                    done: false,
14528                });
14529                self.select_previous(action, window, cx)?;
14530            }
14531        }
14532        Ok(())
14533    }
14534
14535    pub fn find_next_match(
14536        &mut self,
14537        _: &FindNextMatch,
14538        window: &mut Window,
14539        cx: &mut Context<Self>,
14540    ) -> Result<()> {
14541        let selections = self.selections.disjoint_anchors();
14542        match selections.first() {
14543            Some(first) if selections.len() >= 2 => {
14544                self.change_selections(Default::default(), window, cx, |s| {
14545                    s.select_ranges([first.range()]);
14546                });
14547            }
14548            _ => self.select_next(
14549                &SelectNext {
14550                    replace_newest: true,
14551                },
14552                window,
14553                cx,
14554            )?,
14555        }
14556        Ok(())
14557    }
14558
14559    pub fn find_previous_match(
14560        &mut self,
14561        _: &FindPreviousMatch,
14562        window: &mut Window,
14563        cx: &mut Context<Self>,
14564    ) -> Result<()> {
14565        let selections = self.selections.disjoint_anchors();
14566        match selections.last() {
14567            Some(last) if selections.len() >= 2 => {
14568                self.change_selections(Default::default(), window, cx, |s| {
14569                    s.select_ranges([last.range()]);
14570                });
14571            }
14572            _ => self.select_previous(
14573                &SelectPrevious {
14574                    replace_newest: true,
14575                },
14576                window,
14577                cx,
14578            )?,
14579        }
14580        Ok(())
14581    }
14582
14583    pub fn toggle_comments(
14584        &mut self,
14585        action: &ToggleComments,
14586        window: &mut Window,
14587        cx: &mut Context<Self>,
14588    ) {
14589        if self.read_only(cx) {
14590            return;
14591        }
14592        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14593        let text_layout_details = &self.text_layout_details(window);
14594        self.transact(window, cx, |this, window, cx| {
14595            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14596            let mut edits = Vec::new();
14597            let mut selection_edit_ranges = Vec::new();
14598            let mut last_toggled_row = None;
14599            let snapshot = this.buffer.read(cx).read(cx);
14600            let empty_str: Arc<str> = Arc::default();
14601            let mut suffixes_inserted = Vec::new();
14602            let ignore_indent = action.ignore_indent;
14603
14604            fn comment_prefix_range(
14605                snapshot: &MultiBufferSnapshot,
14606                row: MultiBufferRow,
14607                comment_prefix: &str,
14608                comment_prefix_whitespace: &str,
14609                ignore_indent: bool,
14610            ) -> Range<Point> {
14611                let indent_size = if ignore_indent {
14612                    0
14613                } else {
14614                    snapshot.indent_size_for_line(row).len
14615                };
14616
14617                let start = Point::new(row.0, indent_size);
14618
14619                let mut line_bytes = snapshot
14620                    .bytes_in_range(start..snapshot.max_point())
14621                    .flatten()
14622                    .copied();
14623
14624                // If this line currently begins with the line comment prefix, then record
14625                // the range containing the prefix.
14626                if line_bytes
14627                    .by_ref()
14628                    .take(comment_prefix.len())
14629                    .eq(comment_prefix.bytes())
14630                {
14631                    // Include any whitespace that matches the comment prefix.
14632                    let matching_whitespace_len = line_bytes
14633                        .zip(comment_prefix_whitespace.bytes())
14634                        .take_while(|(a, b)| a == b)
14635                        .count() as u32;
14636                    let end = Point::new(
14637                        start.row,
14638                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14639                    );
14640                    start..end
14641                } else {
14642                    start..start
14643                }
14644            }
14645
14646            fn comment_suffix_range(
14647                snapshot: &MultiBufferSnapshot,
14648                row: MultiBufferRow,
14649                comment_suffix: &str,
14650                comment_suffix_has_leading_space: bool,
14651            ) -> Range<Point> {
14652                let end = Point::new(row.0, snapshot.line_len(row));
14653                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14654
14655                let mut line_end_bytes = snapshot
14656                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14657                    .flatten()
14658                    .copied();
14659
14660                let leading_space_len = if suffix_start_column > 0
14661                    && line_end_bytes.next() == Some(b' ')
14662                    && comment_suffix_has_leading_space
14663                {
14664                    1
14665                } else {
14666                    0
14667                };
14668
14669                // If this line currently begins with the line comment prefix, then record
14670                // the range containing the prefix.
14671                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14672                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14673                    start..end
14674                } else {
14675                    end..end
14676                }
14677            }
14678
14679            // TODO: Handle selections that cross excerpts
14680            for selection in &mut selections {
14681                let start_column = snapshot
14682                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14683                    .len;
14684                let language = if let Some(language) =
14685                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14686                {
14687                    language
14688                } else {
14689                    continue;
14690                };
14691
14692                selection_edit_ranges.clear();
14693
14694                // If multiple selections contain a given row, avoid processing that
14695                // row more than once.
14696                let mut start_row = MultiBufferRow(selection.start.row);
14697                if last_toggled_row == Some(start_row) {
14698                    start_row = start_row.next_row();
14699                }
14700                let end_row =
14701                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14702                        MultiBufferRow(selection.end.row - 1)
14703                    } else {
14704                        MultiBufferRow(selection.end.row)
14705                    };
14706                last_toggled_row = Some(end_row);
14707
14708                if start_row > end_row {
14709                    continue;
14710                }
14711
14712                // If the language has line comments, toggle those.
14713                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14714
14715                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14716                if ignore_indent {
14717                    full_comment_prefixes = full_comment_prefixes
14718                        .into_iter()
14719                        .map(|s| Arc::from(s.trim_end()))
14720                        .collect();
14721                }
14722
14723                if !full_comment_prefixes.is_empty() {
14724                    let first_prefix = full_comment_prefixes
14725                        .first()
14726                        .expect("prefixes is non-empty");
14727                    let prefix_trimmed_lengths = full_comment_prefixes
14728                        .iter()
14729                        .map(|p| p.trim_end_matches(' ').len())
14730                        .collect::<SmallVec<[usize; 4]>>();
14731
14732                    let mut all_selection_lines_are_comments = true;
14733
14734                    for row in start_row.0..=end_row.0 {
14735                        let row = MultiBufferRow(row);
14736                        if start_row < end_row && snapshot.is_line_blank(row) {
14737                            continue;
14738                        }
14739
14740                        let prefix_range = full_comment_prefixes
14741                            .iter()
14742                            .zip(prefix_trimmed_lengths.iter().copied())
14743                            .map(|(prefix, trimmed_prefix_len)| {
14744                                comment_prefix_range(
14745                                    snapshot.deref(),
14746                                    row,
14747                                    &prefix[..trimmed_prefix_len],
14748                                    &prefix[trimmed_prefix_len..],
14749                                    ignore_indent,
14750                                )
14751                            })
14752                            .max_by_key(|range| range.end.column - range.start.column)
14753                            .expect("prefixes is non-empty");
14754
14755                        if prefix_range.is_empty() {
14756                            all_selection_lines_are_comments = false;
14757                        }
14758
14759                        selection_edit_ranges.push(prefix_range);
14760                    }
14761
14762                    if all_selection_lines_are_comments {
14763                        edits.extend(
14764                            selection_edit_ranges
14765                                .iter()
14766                                .cloned()
14767                                .map(|range| (range, empty_str.clone())),
14768                        );
14769                    } else {
14770                        let min_column = selection_edit_ranges
14771                            .iter()
14772                            .map(|range| range.start.column)
14773                            .min()
14774                            .unwrap_or(0);
14775                        edits.extend(selection_edit_ranges.iter().map(|range| {
14776                            let position = Point::new(range.start.row, min_column);
14777                            (position..position, first_prefix.clone())
14778                        }));
14779                    }
14780                } else if let Some(BlockCommentConfig {
14781                    start: full_comment_prefix,
14782                    end: comment_suffix,
14783                    ..
14784                }) = language.block_comment()
14785                {
14786                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14787                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14788                    let prefix_range = comment_prefix_range(
14789                        snapshot.deref(),
14790                        start_row,
14791                        comment_prefix,
14792                        comment_prefix_whitespace,
14793                        ignore_indent,
14794                    );
14795                    let suffix_range = comment_suffix_range(
14796                        snapshot.deref(),
14797                        end_row,
14798                        comment_suffix.trim_start_matches(' '),
14799                        comment_suffix.starts_with(' '),
14800                    );
14801
14802                    if prefix_range.is_empty() || suffix_range.is_empty() {
14803                        edits.push((
14804                            prefix_range.start..prefix_range.start,
14805                            full_comment_prefix.clone(),
14806                        ));
14807                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14808                        suffixes_inserted.push((end_row, comment_suffix.len()));
14809                    } else {
14810                        edits.push((prefix_range, empty_str.clone()));
14811                        edits.push((suffix_range, empty_str.clone()));
14812                    }
14813                } else {
14814                    continue;
14815                }
14816            }
14817
14818            drop(snapshot);
14819            this.buffer.update(cx, |buffer, cx| {
14820                buffer.edit(edits, None, cx);
14821            });
14822
14823            // Adjust selections so that they end before any comment suffixes that
14824            // were inserted.
14825            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14826            let mut selections = this.selections.all::<Point>(cx);
14827            let snapshot = this.buffer.read(cx).read(cx);
14828            for selection in &mut selections {
14829                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14830                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14831                        Ordering::Less => {
14832                            suffixes_inserted.next();
14833                            continue;
14834                        }
14835                        Ordering::Greater => break,
14836                        Ordering::Equal => {
14837                            if selection.end.column == snapshot.line_len(row) {
14838                                if selection.is_empty() {
14839                                    selection.start.column -= suffix_len as u32;
14840                                }
14841                                selection.end.column -= suffix_len as u32;
14842                            }
14843                            break;
14844                        }
14845                    }
14846                }
14847            }
14848
14849            drop(snapshot);
14850            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14851
14852            let selections = this.selections.all::<Point>(cx);
14853            let selections_on_single_row = selections.windows(2).all(|selections| {
14854                selections[0].start.row == selections[1].start.row
14855                    && selections[0].end.row == selections[1].end.row
14856                    && selections[0].start.row == selections[0].end.row
14857            });
14858            let selections_selecting = selections
14859                .iter()
14860                .any(|selection| selection.start != selection.end);
14861            let advance_downwards = action.advance_downwards
14862                && selections_on_single_row
14863                && !selections_selecting
14864                && !matches!(this.mode, EditorMode::SingleLine);
14865
14866            if advance_downwards {
14867                let snapshot = this.buffer.read(cx).snapshot(cx);
14868
14869                this.change_selections(Default::default(), window, cx, |s| {
14870                    s.move_cursors_with(|display_snapshot, display_point, _| {
14871                        let mut point = display_point.to_point(display_snapshot);
14872                        point.row += 1;
14873                        point = snapshot.clip_point(point, Bias::Left);
14874                        let display_point = point.to_display_point(display_snapshot);
14875                        let goal = SelectionGoal::HorizontalPosition(
14876                            display_snapshot
14877                                .x_for_display_point(display_point, text_layout_details)
14878                                .into(),
14879                        );
14880                        (display_point, goal)
14881                    })
14882                });
14883            }
14884        });
14885    }
14886
14887    pub fn select_enclosing_symbol(
14888        &mut self,
14889        _: &SelectEnclosingSymbol,
14890        window: &mut Window,
14891        cx: &mut Context<Self>,
14892    ) {
14893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14894
14895        let buffer = self.buffer.read(cx).snapshot(cx);
14896        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14897
14898        fn update_selection(
14899            selection: &Selection<usize>,
14900            buffer_snap: &MultiBufferSnapshot,
14901        ) -> Option<Selection<usize>> {
14902            let cursor = selection.head();
14903            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14904            for symbol in symbols.iter().rev() {
14905                let start = symbol.range.start.to_offset(buffer_snap);
14906                let end = symbol.range.end.to_offset(buffer_snap);
14907                let new_range = start..end;
14908                if start < selection.start || end > selection.end {
14909                    return Some(Selection {
14910                        id: selection.id,
14911                        start: new_range.start,
14912                        end: new_range.end,
14913                        goal: SelectionGoal::None,
14914                        reversed: selection.reversed,
14915                    });
14916                }
14917            }
14918            None
14919        }
14920
14921        let mut selected_larger_symbol = false;
14922        let new_selections = old_selections
14923            .iter()
14924            .map(|selection| match update_selection(selection, &buffer) {
14925                Some(new_selection) => {
14926                    if new_selection.range() != selection.range() {
14927                        selected_larger_symbol = true;
14928                    }
14929                    new_selection
14930                }
14931                None => selection.clone(),
14932            })
14933            .collect::<Vec<_>>();
14934
14935        if selected_larger_symbol {
14936            self.change_selections(Default::default(), window, cx, |s| {
14937                s.select(new_selections);
14938            });
14939        }
14940    }
14941
14942    pub fn select_larger_syntax_node(
14943        &mut self,
14944        _: &SelectLargerSyntaxNode,
14945        window: &mut Window,
14946        cx: &mut Context<Self>,
14947    ) {
14948        let Some(visible_row_count) = self.visible_row_count() else {
14949            return;
14950        };
14951        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14952        if old_selections.is_empty() {
14953            return;
14954        }
14955
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957
14958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14959        let buffer = self.buffer.read(cx).snapshot(cx);
14960
14961        let mut selected_larger_node = false;
14962        let mut new_selections = old_selections
14963            .iter()
14964            .map(|selection| {
14965                let old_range = selection.start..selection.end;
14966
14967                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14968                    // manually select word at selection
14969                    if ["string_content", "inline"].contains(&node.kind()) {
14970                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14971                        // ignore if word is already selected
14972                        if !word_range.is_empty() && old_range != word_range {
14973                            let (last_word_range, _) =
14974                                buffer.surrounding_word(old_range.end, false);
14975                            // only select word if start and end point belongs to same word
14976                            if word_range == last_word_range {
14977                                selected_larger_node = true;
14978                                return Selection {
14979                                    id: selection.id,
14980                                    start: word_range.start,
14981                                    end: word_range.end,
14982                                    goal: SelectionGoal::None,
14983                                    reversed: selection.reversed,
14984                                };
14985                            }
14986                        }
14987                    }
14988                }
14989
14990                let mut new_range = old_range.clone();
14991                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14992                {
14993                    if !node.is_named() {
14994                        new_range = node.start_byte()..node.end_byte();
14995                        continue;
14996                    }
14997
14998                    new_range = match containing_range {
14999                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15000                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15001                    };
15002                    if !display_map.intersects_fold(new_range.start)
15003                        && !display_map.intersects_fold(new_range.end)
15004                    {
15005                        break;
15006                    }
15007                }
15008
15009                selected_larger_node |= new_range != old_range;
15010                Selection {
15011                    id: selection.id,
15012                    start: new_range.start,
15013                    end: new_range.end,
15014                    goal: SelectionGoal::None,
15015                    reversed: selection.reversed,
15016                }
15017            })
15018            .collect::<Vec<_>>();
15019
15020        if !selected_larger_node {
15021            return; // don't put this call in the history
15022        }
15023
15024        // scroll based on transformation done to the last selection created by the user
15025        let (last_old, last_new) = old_selections
15026            .last()
15027            .zip(new_selections.last().cloned())
15028            .expect("old_selections isn't empty");
15029
15030        // revert selection
15031        let is_selection_reversed = {
15032            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15033            new_selections.last_mut().expect("checked above").reversed =
15034                should_newest_selection_be_reversed;
15035            should_newest_selection_be_reversed
15036        };
15037
15038        if selected_larger_node {
15039            self.select_syntax_node_history.disable_clearing = true;
15040            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15041                s.select(new_selections.clone());
15042            });
15043            self.select_syntax_node_history.disable_clearing = false;
15044        }
15045
15046        let start_row = last_new.start.to_display_point(&display_map).row().0;
15047        let end_row = last_new.end.to_display_point(&display_map).row().0;
15048        let selection_height = end_row - start_row + 1;
15049        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15050
15051        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15052        let scroll_behavior = if fits_on_the_screen {
15053            self.request_autoscroll(Autoscroll::fit(), cx);
15054            SelectSyntaxNodeScrollBehavior::FitSelection
15055        } else if is_selection_reversed {
15056            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15057            SelectSyntaxNodeScrollBehavior::CursorTop
15058        } else {
15059            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15060            SelectSyntaxNodeScrollBehavior::CursorBottom
15061        };
15062
15063        self.select_syntax_node_history.push((
15064            old_selections,
15065            scroll_behavior,
15066            is_selection_reversed,
15067        ));
15068    }
15069
15070    pub fn select_smaller_syntax_node(
15071        &mut self,
15072        _: &SelectSmallerSyntaxNode,
15073        window: &mut Window,
15074        cx: &mut Context<Self>,
15075    ) {
15076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15077
15078        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15079            self.select_syntax_node_history.pop()
15080        {
15081            if let Some(selection) = selections.last_mut() {
15082                selection.reversed = is_selection_reversed;
15083            }
15084
15085            self.select_syntax_node_history.disable_clearing = true;
15086            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15087                s.select(selections.to_vec());
15088            });
15089            self.select_syntax_node_history.disable_clearing = false;
15090
15091            match scroll_behavior {
15092                SelectSyntaxNodeScrollBehavior::CursorTop => {
15093                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15094                }
15095                SelectSyntaxNodeScrollBehavior::FitSelection => {
15096                    self.request_autoscroll(Autoscroll::fit(), cx);
15097                }
15098                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15099                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15100                }
15101            }
15102        }
15103    }
15104
15105    pub fn unwrap_syntax_node(
15106        &mut self,
15107        _: &UnwrapSyntaxNode,
15108        window: &mut Window,
15109        cx: &mut Context<Self>,
15110    ) {
15111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15112
15113        let buffer = self.buffer.read(cx).snapshot(cx);
15114        let selections = self
15115            .selections
15116            .all::<usize>(cx)
15117            .into_iter()
15118            // subtracting the offset requires sorting
15119            .sorted_by_key(|i| i.start);
15120
15121        let full_edits = selections
15122            .into_iter()
15123            .filter_map(|selection| {
15124                // Only requires two branches once if-let-chains stabilize (#53667)
15125                let child = if !selection.is_empty() {
15126                    selection.range()
15127                } else if let Some((_, ancestor_range)) =
15128                    buffer.syntax_ancestor(selection.start..selection.end)
15129                {
15130                    match ancestor_range {
15131                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15132                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15133                    }
15134                } else {
15135                    selection.range()
15136                };
15137
15138                let mut parent = child.clone();
15139                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15140                    parent = match ancestor_range {
15141                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15142                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15143                    };
15144                    if parent.start < child.start || parent.end > child.end {
15145                        break;
15146                    }
15147                }
15148
15149                if parent == child {
15150                    return None;
15151                }
15152                let text = buffer.text_for_range(child).collect::<String>();
15153                Some((selection.id, parent, text))
15154            })
15155            .collect::<Vec<_>>();
15156
15157        self.transact(window, cx, |this, window, cx| {
15158            this.buffer.update(cx, |buffer, cx| {
15159                buffer.edit(
15160                    full_edits
15161                        .iter()
15162                        .map(|(_, p, t)| (p.clone(), t.clone()))
15163                        .collect::<Vec<_>>(),
15164                    None,
15165                    cx,
15166                );
15167            });
15168            this.change_selections(Default::default(), window, cx, |s| {
15169                let mut offset = 0;
15170                let mut selections = vec![];
15171                for (id, parent, text) in full_edits {
15172                    let start = parent.start - offset;
15173                    offset += parent.len() - text.len();
15174                    selections.push(Selection {
15175                        id,
15176                        start,
15177                        end: start + text.len(),
15178                        reversed: false,
15179                        goal: Default::default(),
15180                    });
15181                }
15182                s.select(selections);
15183            });
15184        });
15185    }
15186
15187    pub fn select_next_syntax_node(
15188        &mut self,
15189        _: &SelectNextSyntaxNode,
15190        window: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15194        if old_selections.is_empty() {
15195            return;
15196        }
15197
15198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15199
15200        let buffer = self.buffer.read(cx).snapshot(cx);
15201        let mut selected_sibling = false;
15202
15203        let new_selections = old_selections
15204            .iter()
15205            .map(|selection| {
15206                let old_range = selection.start..selection.end;
15207
15208                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15209                    let new_range = node.byte_range();
15210                    selected_sibling = true;
15211                    Selection {
15212                        id: selection.id,
15213                        start: new_range.start,
15214                        end: new_range.end,
15215                        goal: SelectionGoal::None,
15216                        reversed: selection.reversed,
15217                    }
15218                } else {
15219                    selection.clone()
15220                }
15221            })
15222            .collect::<Vec<_>>();
15223
15224        if selected_sibling {
15225            self.change_selections(
15226                SelectionEffects::scroll(Autoscroll::fit()),
15227                window,
15228                cx,
15229                |s| {
15230                    s.select(new_selections);
15231                },
15232            );
15233        }
15234    }
15235
15236    pub fn select_prev_syntax_node(
15237        &mut self,
15238        _: &SelectPreviousSyntaxNode,
15239        window: &mut Window,
15240        cx: &mut Context<Self>,
15241    ) {
15242        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15243        if old_selections.is_empty() {
15244            return;
15245        }
15246
15247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15248
15249        let buffer = self.buffer.read(cx).snapshot(cx);
15250        let mut selected_sibling = false;
15251
15252        let new_selections = old_selections
15253            .iter()
15254            .map(|selection| {
15255                let old_range = selection.start..selection.end;
15256
15257                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15258                    let new_range = node.byte_range();
15259                    selected_sibling = true;
15260                    Selection {
15261                        id: selection.id,
15262                        start: new_range.start,
15263                        end: new_range.end,
15264                        goal: SelectionGoal::None,
15265                        reversed: selection.reversed,
15266                    }
15267                } else {
15268                    selection.clone()
15269                }
15270            })
15271            .collect::<Vec<_>>();
15272
15273        if selected_sibling {
15274            self.change_selections(
15275                SelectionEffects::scroll(Autoscroll::fit()),
15276                window,
15277                cx,
15278                |s| {
15279                    s.select(new_selections);
15280                },
15281            );
15282        }
15283    }
15284
15285    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15286        if !EditorSettings::get_global(cx).gutter.runnables {
15287            self.clear_tasks();
15288            return Task::ready(());
15289        }
15290        let project = self.project().map(Entity::downgrade);
15291        let task_sources = self.lsp_task_sources(cx);
15292        let multi_buffer = self.buffer.downgrade();
15293        cx.spawn_in(window, async move |editor, cx| {
15294            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15295            let Some(project) = project.and_then(|p| p.upgrade()) else {
15296                return;
15297            };
15298            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15299                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15300            }) else {
15301                return;
15302            };
15303
15304            let hide_runnables = project
15305                .update(cx, |project, _| project.is_via_collab())
15306                .unwrap_or(true);
15307            if hide_runnables {
15308                return;
15309            }
15310            let new_rows =
15311                cx.background_spawn({
15312                    let snapshot = display_snapshot.clone();
15313                    async move {
15314                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15315                    }
15316                })
15317                    .await;
15318            let Ok(lsp_tasks) =
15319                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15320            else {
15321                return;
15322            };
15323            let lsp_tasks = lsp_tasks.await;
15324
15325            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15326                lsp_tasks
15327                    .into_iter()
15328                    .flat_map(|(kind, tasks)| {
15329                        tasks.into_iter().filter_map(move |(location, task)| {
15330                            Some((kind.clone(), location?, task))
15331                        })
15332                    })
15333                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15334                        let buffer = location.target.buffer;
15335                        let buffer_snapshot = buffer.read(cx).snapshot();
15336                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15337                            |(excerpt_id, snapshot, _)| {
15338                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15339                                    display_snapshot
15340                                        .buffer_snapshot
15341                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15342                                } else {
15343                                    None
15344                                }
15345                            },
15346                        );
15347                        if let Some(offset) = offset {
15348                            let task_buffer_range =
15349                                location.target.range.to_point(&buffer_snapshot);
15350                            let context_buffer_range =
15351                                task_buffer_range.to_offset(&buffer_snapshot);
15352                            let context_range = BufferOffset(context_buffer_range.start)
15353                                ..BufferOffset(context_buffer_range.end);
15354
15355                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15356                                .or_insert_with(|| RunnableTasks {
15357                                    templates: Vec::new(),
15358                                    offset,
15359                                    column: task_buffer_range.start.column,
15360                                    extra_variables: HashMap::default(),
15361                                    context_range,
15362                                })
15363                                .templates
15364                                .push((kind, task.original_task().clone()));
15365                        }
15366
15367                        acc
15368                    })
15369            }) else {
15370                return;
15371            };
15372
15373            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15374                buffer.language_settings(cx).tasks.prefer_lsp
15375            }) else {
15376                return;
15377            };
15378
15379            let rows = Self::runnable_rows(
15380                project,
15381                display_snapshot,
15382                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15383                new_rows,
15384                cx.clone(),
15385            )
15386            .await;
15387            editor
15388                .update(cx, |editor, _| {
15389                    editor.clear_tasks();
15390                    for (key, mut value) in rows {
15391                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15392                            value.templates.extend(lsp_tasks.templates);
15393                        }
15394
15395                        editor.insert_tasks(key, value);
15396                    }
15397                    for (key, value) in lsp_tasks_by_rows {
15398                        editor.insert_tasks(key, value);
15399                    }
15400                })
15401                .ok();
15402        })
15403    }
15404    fn fetch_runnable_ranges(
15405        snapshot: &DisplaySnapshot,
15406        range: Range<Anchor>,
15407    ) -> Vec<language::RunnableRange> {
15408        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15409    }
15410
15411    fn runnable_rows(
15412        project: Entity<Project>,
15413        snapshot: DisplaySnapshot,
15414        prefer_lsp: bool,
15415        runnable_ranges: Vec<RunnableRange>,
15416        cx: AsyncWindowContext,
15417    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15418        cx.spawn(async move |cx| {
15419            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15420            for mut runnable in runnable_ranges {
15421                let Some(tasks) = cx
15422                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15423                    .ok()
15424                else {
15425                    continue;
15426                };
15427                let mut tasks = tasks.await;
15428
15429                if prefer_lsp {
15430                    tasks.retain(|(task_kind, _)| {
15431                        !matches!(task_kind, TaskSourceKind::Language { .. })
15432                    });
15433                }
15434                if tasks.is_empty() {
15435                    continue;
15436                }
15437
15438                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15439                let Some(row) = snapshot
15440                    .buffer_snapshot
15441                    .buffer_line_for_row(MultiBufferRow(point.row))
15442                    .map(|(_, range)| range.start.row)
15443                else {
15444                    continue;
15445                };
15446
15447                let context_range =
15448                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15449                runnable_rows.push((
15450                    (runnable.buffer_id, row),
15451                    RunnableTasks {
15452                        templates: tasks,
15453                        offset: snapshot
15454                            .buffer_snapshot
15455                            .anchor_before(runnable.run_range.start),
15456                        context_range,
15457                        column: point.column,
15458                        extra_variables: runnable.extra_captures,
15459                    },
15460                ));
15461            }
15462            runnable_rows
15463        })
15464    }
15465
15466    fn templates_with_tags(
15467        project: &Entity<Project>,
15468        runnable: &mut Runnable,
15469        cx: &mut App,
15470    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15471        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15472            let (worktree_id, file) = project
15473                .buffer_for_id(runnable.buffer, cx)
15474                .and_then(|buffer| buffer.read(cx).file())
15475                .map(|file| (file.worktree_id(cx), file.clone()))
15476                .unzip();
15477
15478            (
15479                project.task_store().read(cx).task_inventory().cloned(),
15480                worktree_id,
15481                file,
15482            )
15483        });
15484
15485        let tags = mem::take(&mut runnable.tags);
15486        let language = runnable.language.clone();
15487        cx.spawn(async move |cx| {
15488            let mut templates_with_tags = Vec::new();
15489            if let Some(inventory) = inventory {
15490                for RunnableTag(tag) in tags {
15491                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15492                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15493                    }) else {
15494                        return templates_with_tags;
15495                    };
15496                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15497                        move |(_, template)| {
15498                            template.tags.iter().any(|source_tag| source_tag == &tag)
15499                        },
15500                    ));
15501                }
15502            }
15503            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15504
15505            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15506                // Strongest source wins; if we have worktree tag binding, prefer that to
15507                // global and language bindings;
15508                // if we have a global binding, prefer that to language binding.
15509                let first_mismatch = templates_with_tags
15510                    .iter()
15511                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15512                if let Some(index) = first_mismatch {
15513                    templates_with_tags.truncate(index);
15514                }
15515            }
15516
15517            templates_with_tags
15518        })
15519    }
15520
15521    pub fn move_to_enclosing_bracket(
15522        &mut self,
15523        _: &MoveToEnclosingBracket,
15524        window: &mut Window,
15525        cx: &mut Context<Self>,
15526    ) {
15527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15528        self.change_selections(Default::default(), window, cx, |s| {
15529            s.move_offsets_with(|snapshot, selection| {
15530                let Some(enclosing_bracket_ranges) =
15531                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15532                else {
15533                    return;
15534                };
15535
15536                let mut best_length = usize::MAX;
15537                let mut best_inside = false;
15538                let mut best_in_bracket_range = false;
15539                let mut best_destination = None;
15540                for (open, close) in enclosing_bracket_ranges {
15541                    let close = close.to_inclusive();
15542                    let length = close.end() - open.start;
15543                    let inside = selection.start >= open.end && selection.end <= *close.start();
15544                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15545                        || close.contains(&selection.head());
15546
15547                    // If best is next to a bracket and current isn't, skip
15548                    if !in_bracket_range && best_in_bracket_range {
15549                        continue;
15550                    }
15551
15552                    // Prefer smaller lengths unless best is inside and current isn't
15553                    if length > best_length && (best_inside || !inside) {
15554                        continue;
15555                    }
15556
15557                    best_length = length;
15558                    best_inside = inside;
15559                    best_in_bracket_range = in_bracket_range;
15560                    best_destination = Some(
15561                        if close.contains(&selection.start) && close.contains(&selection.end) {
15562                            if inside { open.end } else { open.start }
15563                        } else if inside {
15564                            *close.start()
15565                        } else {
15566                            *close.end()
15567                        },
15568                    );
15569                }
15570
15571                if let Some(destination) = best_destination {
15572                    selection.collapse_to(destination, SelectionGoal::None);
15573                }
15574            })
15575        });
15576    }
15577
15578    pub fn undo_selection(
15579        &mut self,
15580        _: &UndoSelection,
15581        window: &mut Window,
15582        cx: &mut Context<Self>,
15583    ) {
15584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15585        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15586            self.selection_history.mode = SelectionHistoryMode::Undoing;
15587            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15588                this.end_selection(window, cx);
15589                this.change_selections(
15590                    SelectionEffects::scroll(Autoscroll::newest()),
15591                    window,
15592                    cx,
15593                    |s| s.select_anchors(entry.selections.to_vec()),
15594                );
15595            });
15596            self.selection_history.mode = SelectionHistoryMode::Normal;
15597
15598            self.select_next_state = entry.select_next_state;
15599            self.select_prev_state = entry.select_prev_state;
15600            self.add_selections_state = entry.add_selections_state;
15601        }
15602    }
15603
15604    pub fn redo_selection(
15605        &mut self,
15606        _: &RedoSelection,
15607        window: &mut Window,
15608        cx: &mut Context<Self>,
15609    ) {
15610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15611        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15612            self.selection_history.mode = SelectionHistoryMode::Redoing;
15613            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15614                this.end_selection(window, cx);
15615                this.change_selections(
15616                    SelectionEffects::scroll(Autoscroll::newest()),
15617                    window,
15618                    cx,
15619                    |s| s.select_anchors(entry.selections.to_vec()),
15620                );
15621            });
15622            self.selection_history.mode = SelectionHistoryMode::Normal;
15623
15624            self.select_next_state = entry.select_next_state;
15625            self.select_prev_state = entry.select_prev_state;
15626            self.add_selections_state = entry.add_selections_state;
15627        }
15628    }
15629
15630    pub fn expand_excerpts(
15631        &mut self,
15632        action: &ExpandExcerpts,
15633        _: &mut Window,
15634        cx: &mut Context<Self>,
15635    ) {
15636        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15637    }
15638
15639    pub fn expand_excerpts_down(
15640        &mut self,
15641        action: &ExpandExcerptsDown,
15642        _: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15646    }
15647
15648    pub fn expand_excerpts_up(
15649        &mut self,
15650        action: &ExpandExcerptsUp,
15651        _: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) {
15654        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15655    }
15656
15657    pub fn expand_excerpts_for_direction(
15658        &mut self,
15659        lines: u32,
15660        direction: ExpandExcerptDirection,
15661
15662        cx: &mut Context<Self>,
15663    ) {
15664        let selections = self.selections.disjoint_anchors();
15665
15666        let lines = if lines == 0 {
15667            EditorSettings::get_global(cx).expand_excerpt_lines
15668        } else {
15669            lines
15670        };
15671
15672        self.buffer.update(cx, |buffer, cx| {
15673            let snapshot = buffer.snapshot(cx);
15674            let mut excerpt_ids = selections
15675                .iter()
15676                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15677                .collect::<Vec<_>>();
15678            excerpt_ids.sort();
15679            excerpt_ids.dedup();
15680            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15681        })
15682    }
15683
15684    pub fn expand_excerpt(
15685        &mut self,
15686        excerpt: ExcerptId,
15687        direction: ExpandExcerptDirection,
15688        window: &mut Window,
15689        cx: &mut Context<Self>,
15690    ) {
15691        let current_scroll_position = self.scroll_position(cx);
15692        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15693        let mut should_scroll_up = false;
15694
15695        if direction == ExpandExcerptDirection::Down {
15696            let multi_buffer = self.buffer.read(cx);
15697            let snapshot = multi_buffer.snapshot(cx);
15698            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15699                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15700                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15701            {
15702                let buffer_snapshot = buffer.read(cx).snapshot();
15703                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15704                let last_row = buffer_snapshot.max_point().row;
15705                let lines_below = last_row.saturating_sub(excerpt_end_row);
15706                should_scroll_up = lines_below >= lines_to_expand;
15707            }
15708        }
15709
15710        self.buffer.update(cx, |buffer, cx| {
15711            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15712        });
15713
15714        if should_scroll_up {
15715            let new_scroll_position =
15716                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15717            self.set_scroll_position(new_scroll_position, window, cx);
15718        }
15719    }
15720
15721    pub fn go_to_singleton_buffer_point(
15722        &mut self,
15723        point: Point,
15724        window: &mut Window,
15725        cx: &mut Context<Self>,
15726    ) {
15727        self.go_to_singleton_buffer_range(point..point, window, cx);
15728    }
15729
15730    pub fn go_to_singleton_buffer_range(
15731        &mut self,
15732        range: Range<Point>,
15733        window: &mut Window,
15734        cx: &mut Context<Self>,
15735    ) {
15736        let multibuffer = self.buffer().read(cx);
15737        let Some(buffer) = multibuffer.as_singleton() else {
15738            return;
15739        };
15740        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15741            return;
15742        };
15743        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15744            return;
15745        };
15746        self.change_selections(
15747            SelectionEffects::default().nav_history(true),
15748            window,
15749            cx,
15750            |s| s.select_anchor_ranges([start..end]),
15751        );
15752    }
15753
15754    pub fn go_to_diagnostic(
15755        &mut self,
15756        action: &GoToDiagnostic,
15757        window: &mut Window,
15758        cx: &mut Context<Self>,
15759    ) {
15760        if !self.diagnostics_enabled() {
15761            return;
15762        }
15763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15764        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15765    }
15766
15767    pub fn go_to_prev_diagnostic(
15768        &mut self,
15769        action: &GoToPreviousDiagnostic,
15770        window: &mut Window,
15771        cx: &mut Context<Self>,
15772    ) {
15773        if !self.diagnostics_enabled() {
15774            return;
15775        }
15776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15777        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15778    }
15779
15780    pub fn go_to_diagnostic_impl(
15781        &mut self,
15782        direction: Direction,
15783        severity: GoToDiagnosticSeverityFilter,
15784        window: &mut Window,
15785        cx: &mut Context<Self>,
15786    ) {
15787        let buffer = self.buffer.read(cx).snapshot(cx);
15788        let selection = self.selections.newest::<usize>(cx);
15789
15790        let mut active_group_id = None;
15791        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15792            && active_group.active_range.start.to_offset(&buffer) == selection.start
15793        {
15794            active_group_id = Some(active_group.group_id);
15795        }
15796
15797        fn filtered(
15798            snapshot: EditorSnapshot,
15799            severity: GoToDiagnosticSeverityFilter,
15800            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15801        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15802            diagnostics
15803                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15804                .filter(|entry| entry.range.start != entry.range.end)
15805                .filter(|entry| !entry.diagnostic.is_unnecessary)
15806                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15807        }
15808
15809        let snapshot = self.snapshot(window, cx);
15810        let before = filtered(
15811            snapshot.clone(),
15812            severity,
15813            buffer
15814                .diagnostics_in_range(0..selection.start)
15815                .filter(|entry| entry.range.start <= selection.start),
15816        );
15817        let after = filtered(
15818            snapshot,
15819            severity,
15820            buffer
15821                .diagnostics_in_range(selection.start..buffer.len())
15822                .filter(|entry| entry.range.start >= selection.start),
15823        );
15824
15825        let mut found: Option<DiagnosticEntry<usize>> = None;
15826        if direction == Direction::Prev {
15827            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15828            {
15829                for diagnostic in prev_diagnostics.into_iter().rev() {
15830                    if diagnostic.range.start != selection.start
15831                        || active_group_id
15832                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15833                    {
15834                        found = Some(diagnostic);
15835                        break 'outer;
15836                    }
15837                }
15838            }
15839        } else {
15840            for diagnostic in after.chain(before) {
15841                if diagnostic.range.start != selection.start
15842                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15843                {
15844                    found = Some(diagnostic);
15845                    break;
15846                }
15847            }
15848        }
15849        let Some(next_diagnostic) = found else {
15850            return;
15851        };
15852
15853        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15854        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15855            return;
15856        };
15857        self.change_selections(Default::default(), window, cx, |s| {
15858            s.select_ranges(vec![
15859                next_diagnostic.range.start..next_diagnostic.range.start,
15860            ])
15861        });
15862        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15863        self.refresh_edit_prediction(false, true, window, cx);
15864    }
15865
15866    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15868        let snapshot = self.snapshot(window, cx);
15869        let selection = self.selections.newest::<Point>(cx);
15870        self.go_to_hunk_before_or_after_position(
15871            &snapshot,
15872            selection.head(),
15873            Direction::Next,
15874            window,
15875            cx,
15876        );
15877    }
15878
15879    pub fn go_to_hunk_before_or_after_position(
15880        &mut self,
15881        snapshot: &EditorSnapshot,
15882        position: Point,
15883        direction: Direction,
15884        window: &mut Window,
15885        cx: &mut Context<Editor>,
15886    ) {
15887        let row = if direction == Direction::Next {
15888            self.hunk_after_position(snapshot, position)
15889                .map(|hunk| hunk.row_range.start)
15890        } else {
15891            self.hunk_before_position(snapshot, position)
15892        };
15893
15894        if let Some(row) = row {
15895            let destination = Point::new(row.0, 0);
15896            let autoscroll = Autoscroll::center();
15897
15898            self.unfold_ranges(&[destination..destination], false, false, cx);
15899            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15900                s.select_ranges([destination..destination]);
15901            });
15902        }
15903    }
15904
15905    fn hunk_after_position(
15906        &mut self,
15907        snapshot: &EditorSnapshot,
15908        position: Point,
15909    ) -> Option<MultiBufferDiffHunk> {
15910        snapshot
15911            .buffer_snapshot
15912            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15913            .find(|hunk| hunk.row_range.start.0 > position.row)
15914            .or_else(|| {
15915                snapshot
15916                    .buffer_snapshot
15917                    .diff_hunks_in_range(Point::zero()..position)
15918                    .find(|hunk| hunk.row_range.end.0 < position.row)
15919            })
15920    }
15921
15922    fn go_to_prev_hunk(
15923        &mut self,
15924        _: &GoToPreviousHunk,
15925        window: &mut Window,
15926        cx: &mut Context<Self>,
15927    ) {
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        let snapshot = self.snapshot(window, cx);
15930        let selection = self.selections.newest::<Point>(cx);
15931        self.go_to_hunk_before_or_after_position(
15932            &snapshot,
15933            selection.head(),
15934            Direction::Prev,
15935            window,
15936            cx,
15937        );
15938    }
15939
15940    fn hunk_before_position(
15941        &mut self,
15942        snapshot: &EditorSnapshot,
15943        position: Point,
15944    ) -> Option<MultiBufferRow> {
15945        snapshot
15946            .buffer_snapshot
15947            .diff_hunk_before(position)
15948            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15949    }
15950
15951    fn go_to_next_change(
15952        &mut self,
15953        _: &GoToNextChange,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        if let Some(selections) = self
15958            .change_list
15959            .next_change(1, Direction::Next)
15960            .map(|s| s.to_vec())
15961        {
15962            self.change_selections(Default::default(), window, cx, |s| {
15963                let map = s.display_map();
15964                s.select_display_ranges(selections.iter().map(|a| {
15965                    let point = a.to_display_point(&map);
15966                    point..point
15967                }))
15968            })
15969        }
15970    }
15971
15972    fn go_to_previous_change(
15973        &mut self,
15974        _: &GoToPreviousChange,
15975        window: &mut Window,
15976        cx: &mut Context<Self>,
15977    ) {
15978        if let Some(selections) = self
15979            .change_list
15980            .next_change(1, Direction::Prev)
15981            .map(|s| s.to_vec())
15982        {
15983            self.change_selections(Default::default(), window, cx, |s| {
15984                let map = s.display_map();
15985                s.select_display_ranges(selections.iter().map(|a| {
15986                    let point = a.to_display_point(&map);
15987                    point..point
15988                }))
15989            })
15990        }
15991    }
15992
15993    pub fn go_to_next_document_highlight(
15994        &mut self,
15995        _: &GoToNextDocumentHighlight,
15996        window: &mut Window,
15997        cx: &mut Context<Self>,
15998    ) {
15999        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16000    }
16001
16002    pub fn go_to_prev_document_highlight(
16003        &mut self,
16004        _: &GoToPreviousDocumentHighlight,
16005        window: &mut Window,
16006        cx: &mut Context<Self>,
16007    ) {
16008        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16009    }
16010
16011    pub fn go_to_document_highlight_before_or_after_position(
16012        &mut self,
16013        direction: Direction,
16014        window: &mut Window,
16015        cx: &mut Context<Editor>,
16016    ) {
16017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16018        let snapshot = self.snapshot(window, cx);
16019        let buffer = &snapshot.buffer_snapshot;
16020        let position = self.selections.newest::<Point>(cx).head();
16021        let anchor_position = buffer.anchor_after(position);
16022
16023        // Get all document highlights (both read and write)
16024        let mut all_highlights = Vec::new();
16025
16026        if let Some((_, read_highlights)) = self
16027            .background_highlights
16028            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16029        {
16030            all_highlights.extend(read_highlights.iter());
16031        }
16032
16033        if let Some((_, write_highlights)) = self
16034            .background_highlights
16035            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16036        {
16037            all_highlights.extend(write_highlights.iter());
16038        }
16039
16040        if all_highlights.is_empty() {
16041            return;
16042        }
16043
16044        // Sort highlights by position
16045        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16046
16047        let target_highlight = match direction {
16048            Direction::Next => {
16049                // Find the first highlight after the current position
16050                all_highlights
16051                    .iter()
16052                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16053            }
16054            Direction::Prev => {
16055                // Find the last highlight before the current position
16056                all_highlights
16057                    .iter()
16058                    .rev()
16059                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16060            }
16061        };
16062
16063        if let Some(highlight) = target_highlight {
16064            let destination = highlight.start.to_point(buffer);
16065            let autoscroll = Autoscroll::center();
16066
16067            self.unfold_ranges(&[destination..destination], false, false, cx);
16068            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16069                s.select_ranges([destination..destination]);
16070            });
16071        }
16072    }
16073
16074    fn go_to_line<T: 'static>(
16075        &mut self,
16076        position: Anchor,
16077        highlight_color: Option<Hsla>,
16078        window: &mut Window,
16079        cx: &mut Context<Self>,
16080    ) {
16081        let snapshot = self.snapshot(window, cx).display_snapshot;
16082        let position = position.to_point(&snapshot.buffer_snapshot);
16083        let start = snapshot
16084            .buffer_snapshot
16085            .clip_point(Point::new(position.row, 0), Bias::Left);
16086        let end = start + Point::new(1, 0);
16087        let start = snapshot.buffer_snapshot.anchor_before(start);
16088        let end = snapshot.buffer_snapshot.anchor_before(end);
16089
16090        self.highlight_rows::<T>(
16091            start..end,
16092            highlight_color
16093                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16094            Default::default(),
16095            cx,
16096        );
16097
16098        if self.buffer.read(cx).is_singleton() {
16099            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16100        }
16101    }
16102
16103    pub fn go_to_definition(
16104        &mut self,
16105        _: &GoToDefinition,
16106        window: &mut Window,
16107        cx: &mut Context<Self>,
16108    ) -> Task<Result<Navigated>> {
16109        let definition =
16110            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16111        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16112        cx.spawn_in(window, async move |editor, cx| {
16113            if definition.await? == Navigated::Yes {
16114                return Ok(Navigated::Yes);
16115            }
16116            match fallback_strategy {
16117                GoToDefinitionFallback::None => Ok(Navigated::No),
16118                GoToDefinitionFallback::FindAllReferences => {
16119                    match editor.update_in(cx, |editor, window, cx| {
16120                        editor.find_all_references(&FindAllReferences, window, cx)
16121                    })? {
16122                        Some(references) => references.await,
16123                        None => Ok(Navigated::No),
16124                    }
16125                }
16126            }
16127        })
16128    }
16129
16130    pub fn go_to_declaration(
16131        &mut self,
16132        _: &GoToDeclaration,
16133        window: &mut Window,
16134        cx: &mut Context<Self>,
16135    ) -> Task<Result<Navigated>> {
16136        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16137    }
16138
16139    pub fn go_to_declaration_split(
16140        &mut self,
16141        _: &GoToDeclaration,
16142        window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) -> Task<Result<Navigated>> {
16145        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16146    }
16147
16148    pub fn go_to_implementation(
16149        &mut self,
16150        _: &GoToImplementation,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) -> Task<Result<Navigated>> {
16154        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16155    }
16156
16157    pub fn go_to_implementation_split(
16158        &mut self,
16159        _: &GoToImplementationSplit,
16160        window: &mut Window,
16161        cx: &mut Context<Self>,
16162    ) -> Task<Result<Navigated>> {
16163        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16164    }
16165
16166    pub fn go_to_type_definition(
16167        &mut self,
16168        _: &GoToTypeDefinition,
16169        window: &mut Window,
16170        cx: &mut Context<Self>,
16171    ) -> Task<Result<Navigated>> {
16172        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16173    }
16174
16175    pub fn go_to_definition_split(
16176        &mut self,
16177        _: &GoToDefinitionSplit,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) -> Task<Result<Navigated>> {
16181        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16182    }
16183
16184    pub fn go_to_type_definition_split(
16185        &mut self,
16186        _: &GoToTypeDefinitionSplit,
16187        window: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) -> Task<Result<Navigated>> {
16190        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16191    }
16192
16193    fn go_to_definition_of_kind(
16194        &mut self,
16195        kind: GotoDefinitionKind,
16196        split: bool,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) -> Task<Result<Navigated>> {
16200        let Some(provider) = self.semantics_provider.clone() else {
16201            return Task::ready(Ok(Navigated::No));
16202        };
16203        let head = self.selections.newest::<usize>(cx).head();
16204        let buffer = self.buffer.read(cx);
16205        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16206            return Task::ready(Ok(Navigated::No));
16207        };
16208        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16209            return Task::ready(Ok(Navigated::No));
16210        };
16211
16212        cx.spawn_in(window, async move |editor, cx| {
16213            let Some(definitions) = definitions.await? else {
16214                return Ok(Navigated::No);
16215            };
16216            let navigated = editor
16217                .update_in(cx, |editor, window, cx| {
16218                    editor.navigate_to_hover_links(
16219                        Some(kind),
16220                        definitions
16221                            .into_iter()
16222                            .filter(|location| {
16223                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16224                            })
16225                            .map(HoverLink::Text)
16226                            .collect::<Vec<_>>(),
16227                        split,
16228                        window,
16229                        cx,
16230                    )
16231                })?
16232                .await?;
16233            anyhow::Ok(navigated)
16234        })
16235    }
16236
16237    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16238        let selection = self.selections.newest_anchor();
16239        let head = selection.head();
16240        let tail = selection.tail();
16241
16242        let Some((buffer, start_position)) =
16243            self.buffer.read(cx).text_anchor_for_position(head, cx)
16244        else {
16245            return;
16246        };
16247
16248        let end_position = if head != tail {
16249            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16250                return;
16251            };
16252            Some(pos)
16253        } else {
16254            None
16255        };
16256
16257        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16258            let url = if let Some(end_pos) = end_position {
16259                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16260            } else {
16261                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16262            };
16263
16264            if let Some(url) = url {
16265                editor.update(cx, |_, cx| {
16266                    cx.open_url(&url);
16267                })
16268            } else {
16269                Ok(())
16270            }
16271        });
16272
16273        url_finder.detach();
16274    }
16275
16276    pub fn open_selected_filename(
16277        &mut self,
16278        _: &OpenSelectedFilename,
16279        window: &mut Window,
16280        cx: &mut Context<Self>,
16281    ) {
16282        let Some(workspace) = self.workspace() else {
16283            return;
16284        };
16285
16286        let position = self.selections.newest_anchor().head();
16287
16288        let Some((buffer, buffer_position)) =
16289            self.buffer.read(cx).text_anchor_for_position(position, cx)
16290        else {
16291            return;
16292        };
16293
16294        let project = self.project.clone();
16295
16296        cx.spawn_in(window, async move |_, cx| {
16297            let result = find_file(&buffer, project, buffer_position, cx).await;
16298
16299            if let Some((_, path)) = result {
16300                workspace
16301                    .update_in(cx, |workspace, window, cx| {
16302                        workspace.open_resolved_path(path, window, cx)
16303                    })?
16304                    .await?;
16305            }
16306            anyhow::Ok(())
16307        })
16308        .detach();
16309    }
16310
16311    pub(crate) fn navigate_to_hover_links(
16312        &mut self,
16313        kind: Option<GotoDefinitionKind>,
16314        definitions: Vec<HoverLink>,
16315        split: bool,
16316        window: &mut Window,
16317        cx: &mut Context<Editor>,
16318    ) -> Task<Result<Navigated>> {
16319        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16320        let mut first_url_or_file = None;
16321        let definitions: Vec<_> = definitions
16322            .into_iter()
16323            .filter_map(|def| match def {
16324                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16325                HoverLink::InlayHint(lsp_location, server_id) => {
16326                    let computation =
16327                        self.compute_target_location(lsp_location, server_id, window, cx);
16328                    Some(cx.background_spawn(computation))
16329                }
16330                HoverLink::Url(url) => {
16331                    first_url_or_file = Some(Either::Left(url));
16332                    None
16333                }
16334                HoverLink::File(path) => {
16335                    first_url_or_file = Some(Either::Right(path));
16336                    None
16337                }
16338            })
16339            .collect();
16340
16341        let workspace = self.workspace();
16342
16343        cx.spawn_in(window, async move |editor, acx| {
16344            let mut locations: Vec<Location> = future::join_all(definitions)
16345                .await
16346                .into_iter()
16347                .filter_map(|location| location.transpose())
16348                .collect::<Result<_>>()
16349                .context("location tasks")?;
16350
16351            if locations.len() > 1 {
16352                let Some(workspace) = workspace else {
16353                    return Ok(Navigated::No);
16354                };
16355
16356                let tab_kind = match kind {
16357                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16358                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16359                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16360                    Some(GotoDefinitionKind::Type) => "Types",
16361                };
16362                let title = editor
16363                    .update_in(acx, |_, _, cx| {
16364                        let target = locations
16365                            .iter()
16366                            .map(|location| {
16367                                location
16368                                    .buffer
16369                                    .read(cx)
16370                                    .text_for_range(location.range.clone())
16371                                    .collect::<String>()
16372                            })
16373                            .filter(|text| !text.contains('\n'))
16374                            .unique()
16375                            .take(3)
16376                            .join(", ");
16377                        if target.is_empty() {
16378                            tab_kind.to_owned()
16379                        } else {
16380                            format!("{tab_kind} for {target}")
16381                        }
16382                    })
16383                    .context("buffer title")?;
16384
16385                let opened = workspace
16386                    .update_in(acx, |workspace, window, cx| {
16387                        Self::open_locations_in_multibuffer(
16388                            workspace,
16389                            locations,
16390                            title,
16391                            split,
16392                            MultibufferSelectionMode::First,
16393                            window,
16394                            cx,
16395                        )
16396                    })
16397                    .is_ok();
16398
16399                anyhow::Ok(Navigated::from_bool(opened))
16400            } else if locations.is_empty() {
16401                // If there is one url or file, open it directly
16402                match first_url_or_file {
16403                    Some(Either::Left(url)) => {
16404                        acx.update(|_, cx| cx.open_url(&url))?;
16405                        Ok(Navigated::Yes)
16406                    }
16407                    Some(Either::Right(path)) => {
16408                        let Some(workspace) = workspace else {
16409                            return Ok(Navigated::No);
16410                        };
16411
16412                        workspace
16413                            .update_in(acx, |workspace, window, cx| {
16414                                workspace.open_resolved_path(path, window, cx)
16415                            })?
16416                            .await?;
16417                        Ok(Navigated::Yes)
16418                    }
16419                    None => Ok(Navigated::No),
16420                }
16421            } else {
16422                let Some(workspace) = workspace else {
16423                    return Ok(Navigated::No);
16424                };
16425
16426                let target = locations.pop().unwrap();
16427                editor.update_in(acx, |editor, window, cx| {
16428                    let range = target.range.to_point(target.buffer.read(cx));
16429                    let range = editor.range_for_match(&range);
16430                    let range = collapse_multiline_range(range);
16431
16432                    if !split
16433                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16434                    {
16435                        editor.go_to_singleton_buffer_range(range, window, cx);
16436                    } else {
16437                        let pane = workspace.read(cx).active_pane().clone();
16438                        window.defer(cx, move |window, cx| {
16439                            let target_editor: Entity<Self> =
16440                                workspace.update(cx, |workspace, cx| {
16441                                    let pane = if split {
16442                                        workspace.adjacent_pane(window, cx)
16443                                    } else {
16444                                        workspace.active_pane().clone()
16445                                    };
16446
16447                                    workspace.open_project_item(
16448                                        pane,
16449                                        target.buffer.clone(),
16450                                        true,
16451                                        true,
16452                                        window,
16453                                        cx,
16454                                    )
16455                                });
16456                            target_editor.update(cx, |target_editor, cx| {
16457                                // When selecting a definition in a different buffer, disable the nav history
16458                                // to avoid creating a history entry at the previous cursor location.
16459                                pane.update(cx, |pane, _| pane.disable_history());
16460                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16461                                pane.update(cx, |pane, _| pane.enable_history());
16462                            });
16463                        });
16464                    }
16465                    Navigated::Yes
16466                })
16467            }
16468        })
16469    }
16470
16471    fn compute_target_location(
16472        &self,
16473        lsp_location: lsp::Location,
16474        server_id: LanguageServerId,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) -> Task<anyhow::Result<Option<Location>>> {
16478        let Some(project) = self.project.clone() else {
16479            return Task::ready(Ok(None));
16480        };
16481
16482        cx.spawn_in(window, async move |editor, cx| {
16483            let location_task = editor.update(cx, |_, cx| {
16484                project.update(cx, |project, cx| {
16485                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16486                })
16487            })?;
16488            let location = Some({
16489                let target_buffer_handle = location_task.await.context("open local buffer")?;
16490                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16491                    let target_start = target_buffer
16492                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16493                    let target_end = target_buffer
16494                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16495                    target_buffer.anchor_after(target_start)
16496                        ..target_buffer.anchor_before(target_end)
16497                })?;
16498                Location {
16499                    buffer: target_buffer_handle,
16500                    range,
16501                }
16502            });
16503            Ok(location)
16504        })
16505    }
16506
16507    pub fn find_all_references(
16508        &mut self,
16509        _: &FindAllReferences,
16510        window: &mut Window,
16511        cx: &mut Context<Self>,
16512    ) -> Option<Task<Result<Navigated>>> {
16513        let selection = self.selections.newest::<usize>(cx);
16514        let multi_buffer = self.buffer.read(cx);
16515        let head = selection.head();
16516
16517        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16518        let head_anchor = multi_buffer_snapshot.anchor_at(
16519            head,
16520            if head < selection.tail() {
16521                Bias::Right
16522            } else {
16523                Bias::Left
16524            },
16525        );
16526
16527        match self
16528            .find_all_references_task_sources
16529            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16530        {
16531            Ok(_) => {
16532                log::info!(
16533                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16534                );
16535                return None;
16536            }
16537            Err(i) => {
16538                self.find_all_references_task_sources.insert(i, head_anchor);
16539            }
16540        }
16541
16542        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16543        let workspace = self.workspace()?;
16544        let project = workspace.read(cx).project().clone();
16545        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16546        Some(cx.spawn_in(window, async move |editor, cx| {
16547            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16548                if let Ok(i) = editor
16549                    .find_all_references_task_sources
16550                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16551                {
16552                    editor.find_all_references_task_sources.remove(i);
16553                }
16554            });
16555
16556            let Some(locations) = references.await? else {
16557                return anyhow::Ok(Navigated::No);
16558            };
16559            if locations.is_empty() {
16560                return anyhow::Ok(Navigated::No);
16561            }
16562
16563            workspace.update_in(cx, |workspace, window, cx| {
16564                let target = locations
16565                    .iter()
16566                    .map(|location| {
16567                        location
16568                            .buffer
16569                            .read(cx)
16570                            .text_for_range(location.range.clone())
16571                            .collect::<String>()
16572                    })
16573                    .filter(|text| !text.contains('\n'))
16574                    .unique()
16575                    .take(3)
16576                    .join(", ");
16577                let title = if target.is_empty() {
16578                    "References".to_owned()
16579                } else {
16580                    format!("References to {target}")
16581                };
16582                Self::open_locations_in_multibuffer(
16583                    workspace,
16584                    locations,
16585                    title,
16586                    false,
16587                    MultibufferSelectionMode::First,
16588                    window,
16589                    cx,
16590                );
16591                Navigated::Yes
16592            })
16593        }))
16594    }
16595
16596    /// Opens a multibuffer with the given project locations in it
16597    pub fn open_locations_in_multibuffer(
16598        workspace: &mut Workspace,
16599        mut locations: Vec<Location>,
16600        title: String,
16601        split: bool,
16602        multibuffer_selection_mode: MultibufferSelectionMode,
16603        window: &mut Window,
16604        cx: &mut Context<Workspace>,
16605    ) {
16606        if locations.is_empty() {
16607            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16608            return;
16609        }
16610
16611        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16612
16613        let mut locations = locations.into_iter().peekable();
16614        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16615        let capability = workspace.project().read(cx).capability();
16616
16617        // a key to find existing multibuffer editors with the same set of locations
16618        // to prevent us from opening more and more multibuffer tabs for searches and the like
16619        let mut key = (title.clone(), vec![]);
16620        let excerpt_buffer = cx.new(|cx| {
16621            let key = &mut key.1;
16622            let mut multibuffer = MultiBuffer::new(capability);
16623            while let Some(location) = locations.next() {
16624                let buffer = location.buffer.read(cx);
16625                let mut ranges_for_buffer = Vec::new();
16626                let range = location.range.to_point(buffer);
16627                ranges_for_buffer.push(range.clone());
16628
16629                while let Some(next_location) =
16630                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16631                {
16632                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16633                }
16634
16635                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16636                key.push((
16637                    location.buffer.read(cx).remote_id(),
16638                    ranges_for_buffer.clone(),
16639                ));
16640                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16641                    PathKey::for_buffer(&location.buffer, cx),
16642                    location.buffer.clone(),
16643                    ranges_for_buffer,
16644                    multibuffer_context_lines(cx),
16645                    cx,
16646                );
16647                ranges.extend(new_ranges)
16648            }
16649
16650            multibuffer.with_title(title)
16651        });
16652        let existing = workspace.active_pane().update(cx, |pane, cx| {
16653            pane.items()
16654                .filter_map(|item| item.downcast::<Editor>())
16655                .find(|editor| {
16656                    editor
16657                        .read(cx)
16658                        .lookup_key
16659                        .as_ref()
16660                        .and_then(|it| {
16661                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16662                        })
16663                        .is_some_and(|it| *it == key)
16664                })
16665        });
16666        let editor = existing.unwrap_or_else(|| {
16667            cx.new(|cx| {
16668                let mut editor = Editor::for_multibuffer(
16669                    excerpt_buffer,
16670                    Some(workspace.project().clone()),
16671                    window,
16672                    cx,
16673                );
16674                editor.lookup_key = Some(Box::new(key));
16675                editor
16676            })
16677        });
16678        editor.update(cx, |editor, cx| {
16679            match multibuffer_selection_mode {
16680                MultibufferSelectionMode::First => {
16681                    if let Some(first_range) = ranges.first() {
16682                        editor.change_selections(
16683                            SelectionEffects::no_scroll(),
16684                            window,
16685                            cx,
16686                            |selections| {
16687                                selections.clear_disjoint();
16688                                selections
16689                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16690                            },
16691                        );
16692                    }
16693                    editor.highlight_background::<Self>(
16694                        &ranges,
16695                        |theme| theme.colors().editor_highlighted_line_background,
16696                        cx,
16697                    );
16698                }
16699                MultibufferSelectionMode::All => {
16700                    editor.change_selections(
16701                        SelectionEffects::no_scroll(),
16702                        window,
16703                        cx,
16704                        |selections| {
16705                            selections.clear_disjoint();
16706                            selections.select_anchor_ranges(ranges);
16707                        },
16708                    );
16709                }
16710            }
16711            editor.register_buffers_with_language_servers(cx);
16712        });
16713
16714        let item = Box::new(editor);
16715        let item_id = item.item_id();
16716
16717        if split {
16718            workspace.split_item(SplitDirection::Right, item, window, cx);
16719        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16720            let (preview_item_id, preview_item_idx) =
16721                workspace.active_pane().read_with(cx, |pane, _| {
16722                    (pane.preview_item_id(), pane.preview_item_idx())
16723                });
16724
16725            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16726
16727            if let Some(preview_item_id) = preview_item_id {
16728                workspace.active_pane().update(cx, |pane, cx| {
16729                    pane.remove_item(preview_item_id, false, false, window, cx);
16730                });
16731            }
16732        } else {
16733            workspace.add_item_to_active_pane(item, None, true, window, cx);
16734        }
16735        workspace.active_pane().update(cx, |pane, cx| {
16736            pane.set_preview_item_id(Some(item_id), cx);
16737        });
16738    }
16739
16740    pub fn rename(
16741        &mut self,
16742        _: &Rename,
16743        window: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) -> Option<Task<Result<()>>> {
16746        use language::ToOffset as _;
16747
16748        let provider = self.semantics_provider.clone()?;
16749        let selection = self.selections.newest_anchor().clone();
16750        let (cursor_buffer, cursor_buffer_position) = self
16751            .buffer
16752            .read(cx)
16753            .text_anchor_for_position(selection.head(), cx)?;
16754        let (tail_buffer, cursor_buffer_position_end) = self
16755            .buffer
16756            .read(cx)
16757            .text_anchor_for_position(selection.tail(), cx)?;
16758        if tail_buffer != cursor_buffer {
16759            return None;
16760        }
16761
16762        let snapshot = cursor_buffer.read(cx).snapshot();
16763        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16764        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16765        let prepare_rename = provider
16766            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16767            .unwrap_or_else(|| Task::ready(Ok(None)));
16768        drop(snapshot);
16769
16770        Some(cx.spawn_in(window, async move |this, cx| {
16771            let rename_range = if let Some(range) = prepare_rename.await? {
16772                Some(range)
16773            } else {
16774                this.update(cx, |this, cx| {
16775                    let buffer = this.buffer.read(cx).snapshot(cx);
16776                    let mut buffer_highlights = this
16777                        .document_highlights_for_position(selection.head(), &buffer)
16778                        .filter(|highlight| {
16779                            highlight.start.excerpt_id == selection.head().excerpt_id
16780                                && highlight.end.excerpt_id == selection.head().excerpt_id
16781                        });
16782                    buffer_highlights
16783                        .next()
16784                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16785                })?
16786            };
16787            if let Some(rename_range) = rename_range {
16788                this.update_in(cx, |this, window, cx| {
16789                    let snapshot = cursor_buffer.read(cx).snapshot();
16790                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16791                    let cursor_offset_in_rename_range =
16792                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16793                    let cursor_offset_in_rename_range_end =
16794                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16795
16796                    this.take_rename(false, window, cx);
16797                    let buffer = this.buffer.read(cx).read(cx);
16798                    let cursor_offset = selection.head().to_offset(&buffer);
16799                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16800                    let rename_end = rename_start + rename_buffer_range.len();
16801                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16802                    let mut old_highlight_id = None;
16803                    let old_name: Arc<str> = buffer
16804                        .chunks(rename_start..rename_end, true)
16805                        .map(|chunk| {
16806                            if old_highlight_id.is_none() {
16807                                old_highlight_id = chunk.syntax_highlight_id;
16808                            }
16809                            chunk.text
16810                        })
16811                        .collect::<String>()
16812                        .into();
16813
16814                    drop(buffer);
16815
16816                    // Position the selection in the rename editor so that it matches the current selection.
16817                    this.show_local_selections = false;
16818                    let rename_editor = cx.new(|cx| {
16819                        let mut editor = Editor::single_line(window, cx);
16820                        editor.buffer.update(cx, |buffer, cx| {
16821                            buffer.edit([(0..0, old_name.clone())], None, cx)
16822                        });
16823                        let rename_selection_range = match cursor_offset_in_rename_range
16824                            .cmp(&cursor_offset_in_rename_range_end)
16825                        {
16826                            Ordering::Equal => {
16827                                editor.select_all(&SelectAll, window, cx);
16828                                return editor;
16829                            }
16830                            Ordering::Less => {
16831                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16832                            }
16833                            Ordering::Greater => {
16834                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16835                            }
16836                        };
16837                        if rename_selection_range.end > old_name.len() {
16838                            editor.select_all(&SelectAll, window, cx);
16839                        } else {
16840                            editor.change_selections(Default::default(), window, cx, |s| {
16841                                s.select_ranges([rename_selection_range]);
16842                            });
16843                        }
16844                        editor
16845                    });
16846                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16847                        if e == &EditorEvent::Focused {
16848                            cx.emit(EditorEvent::FocusedIn)
16849                        }
16850                    })
16851                    .detach();
16852
16853                    let write_highlights =
16854                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16855                    let read_highlights =
16856                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16857                    let ranges = write_highlights
16858                        .iter()
16859                        .flat_map(|(_, ranges)| ranges.iter())
16860                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16861                        .cloned()
16862                        .collect();
16863
16864                    this.highlight_text::<Rename>(
16865                        ranges,
16866                        HighlightStyle {
16867                            fade_out: Some(0.6),
16868                            ..Default::default()
16869                        },
16870                        cx,
16871                    );
16872                    let rename_focus_handle = rename_editor.focus_handle(cx);
16873                    window.focus(&rename_focus_handle);
16874                    let block_id = this.insert_blocks(
16875                        [BlockProperties {
16876                            style: BlockStyle::Flex,
16877                            placement: BlockPlacement::Below(range.start),
16878                            height: Some(1),
16879                            render: Arc::new({
16880                                let rename_editor = rename_editor.clone();
16881                                move |cx: &mut BlockContext| {
16882                                    let mut text_style = cx.editor_style.text.clone();
16883                                    if let Some(highlight_style) = old_highlight_id
16884                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16885                                    {
16886                                        text_style = text_style.highlight(highlight_style);
16887                                    }
16888                                    div()
16889                                        .block_mouse_except_scroll()
16890                                        .pl(cx.anchor_x)
16891                                        .child(EditorElement::new(
16892                                            &rename_editor,
16893                                            EditorStyle {
16894                                                background: cx.theme().system().transparent,
16895                                                local_player: cx.editor_style.local_player,
16896                                                text: text_style,
16897                                                scrollbar_width: cx.editor_style.scrollbar_width,
16898                                                syntax: cx.editor_style.syntax.clone(),
16899                                                status: cx.editor_style.status.clone(),
16900                                                inlay_hints_style: HighlightStyle {
16901                                                    font_weight: Some(FontWeight::BOLD),
16902                                                    ..make_inlay_hints_style(cx.app)
16903                                                },
16904                                                edit_prediction_styles: make_suggestion_styles(
16905                                                    cx.app,
16906                                                ),
16907                                                ..EditorStyle::default()
16908                                            },
16909                                        ))
16910                                        .into_any_element()
16911                                }
16912                            }),
16913                            priority: 0,
16914                        }],
16915                        Some(Autoscroll::fit()),
16916                        cx,
16917                    )[0];
16918                    this.pending_rename = Some(RenameState {
16919                        range,
16920                        old_name,
16921                        editor: rename_editor,
16922                        block_id,
16923                    });
16924                })?;
16925            }
16926
16927            Ok(())
16928        }))
16929    }
16930
16931    pub fn confirm_rename(
16932        &mut self,
16933        _: &ConfirmRename,
16934        window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) -> Option<Task<Result<()>>> {
16937        let rename = self.take_rename(false, window, cx)?;
16938        let workspace = self.workspace()?.downgrade();
16939        let (buffer, start) = self
16940            .buffer
16941            .read(cx)
16942            .text_anchor_for_position(rename.range.start, cx)?;
16943        let (end_buffer, _) = self
16944            .buffer
16945            .read(cx)
16946            .text_anchor_for_position(rename.range.end, cx)?;
16947        if buffer != end_buffer {
16948            return None;
16949        }
16950
16951        let old_name = rename.old_name;
16952        let new_name = rename.editor.read(cx).text(cx);
16953
16954        let rename = self.semantics_provider.as_ref()?.perform_rename(
16955            &buffer,
16956            start,
16957            new_name.clone(),
16958            cx,
16959        )?;
16960
16961        Some(cx.spawn_in(window, async move |editor, cx| {
16962            let project_transaction = rename.await?;
16963            Self::open_project_transaction(
16964                &editor,
16965                workspace,
16966                project_transaction,
16967                format!("Rename: {}{}", old_name, new_name),
16968                cx,
16969            )
16970            .await?;
16971
16972            editor.update(cx, |editor, cx| {
16973                editor.refresh_document_highlights(cx);
16974            })?;
16975            Ok(())
16976        }))
16977    }
16978
16979    fn take_rename(
16980        &mut self,
16981        moving_cursor: bool,
16982        window: &mut Window,
16983        cx: &mut Context<Self>,
16984    ) -> Option<RenameState> {
16985        let rename = self.pending_rename.take()?;
16986        if rename.editor.focus_handle(cx).is_focused(window) {
16987            window.focus(&self.focus_handle);
16988        }
16989
16990        self.remove_blocks(
16991            [rename.block_id].into_iter().collect(),
16992            Some(Autoscroll::fit()),
16993            cx,
16994        );
16995        self.clear_highlights::<Rename>(cx);
16996        self.show_local_selections = true;
16997
16998        if moving_cursor {
16999            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17000                editor.selections.newest::<usize>(cx).head()
17001            });
17002
17003            // Update the selection to match the position of the selection inside
17004            // the rename editor.
17005            let snapshot = self.buffer.read(cx).read(cx);
17006            let rename_range = rename.range.to_offset(&snapshot);
17007            let cursor_in_editor = snapshot
17008                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17009                .min(rename_range.end);
17010            drop(snapshot);
17011
17012            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17013                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17014            });
17015        } else {
17016            self.refresh_document_highlights(cx);
17017        }
17018
17019        Some(rename)
17020    }
17021
17022    pub fn pending_rename(&self) -> Option<&RenameState> {
17023        self.pending_rename.as_ref()
17024    }
17025
17026    fn format(
17027        &mut self,
17028        _: &Format,
17029        window: &mut Window,
17030        cx: &mut Context<Self>,
17031    ) -> Option<Task<Result<()>>> {
17032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17033
17034        let project = match &self.project {
17035            Some(project) => project.clone(),
17036            None => return None,
17037        };
17038
17039        Some(self.perform_format(
17040            project,
17041            FormatTrigger::Manual,
17042            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17043            window,
17044            cx,
17045        ))
17046    }
17047
17048    fn format_selections(
17049        &mut self,
17050        _: &FormatSelections,
17051        window: &mut Window,
17052        cx: &mut Context<Self>,
17053    ) -> Option<Task<Result<()>>> {
17054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17055
17056        let project = match &self.project {
17057            Some(project) => project.clone(),
17058            None => return None,
17059        };
17060
17061        let ranges = self
17062            .selections
17063            .all_adjusted(cx)
17064            .into_iter()
17065            .map(|selection| selection.range())
17066            .collect_vec();
17067
17068        Some(self.perform_format(
17069            project,
17070            FormatTrigger::Manual,
17071            FormatTarget::Ranges(ranges),
17072            window,
17073            cx,
17074        ))
17075    }
17076
17077    fn perform_format(
17078        &mut self,
17079        project: Entity<Project>,
17080        trigger: FormatTrigger,
17081        target: FormatTarget,
17082        window: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) -> Task<Result<()>> {
17085        let buffer = self.buffer.clone();
17086        let (buffers, target) = match target {
17087            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17088            FormatTarget::Ranges(selection_ranges) => {
17089                let multi_buffer = buffer.read(cx);
17090                let snapshot = multi_buffer.read(cx);
17091                let mut buffers = HashSet::default();
17092                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17093                    BTreeMap::new();
17094                for selection_range in selection_ranges {
17095                    for (buffer, buffer_range, _) in
17096                        snapshot.range_to_buffer_ranges(selection_range)
17097                    {
17098                        let buffer_id = buffer.remote_id();
17099                        let start = buffer.anchor_before(buffer_range.start);
17100                        let end = buffer.anchor_after(buffer_range.end);
17101                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17102                        buffer_id_to_ranges
17103                            .entry(buffer_id)
17104                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17105                            .or_insert_with(|| vec![start..end]);
17106                    }
17107                }
17108                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17109            }
17110        };
17111
17112        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17113        let selections_prev = transaction_id_prev
17114            .and_then(|transaction_id_prev| {
17115                // default to selections as they were after the last edit, if we have them,
17116                // instead of how they are now.
17117                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17118                // will take you back to where you made the last edit, instead of staying where you scrolled
17119                self.selection_history
17120                    .transaction(transaction_id_prev)
17121                    .map(|t| t.0.clone())
17122            })
17123            .unwrap_or_else(|| self.selections.disjoint_anchors());
17124
17125        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17126        let format = project.update(cx, |project, cx| {
17127            project.format(buffers, target, true, trigger, cx)
17128        });
17129
17130        cx.spawn_in(window, async move |editor, cx| {
17131            let transaction = futures::select_biased! {
17132                transaction = format.log_err().fuse() => transaction,
17133                () = timeout => {
17134                    log::warn!("timed out waiting for formatting");
17135                    None
17136                }
17137            };
17138
17139            buffer
17140                .update(cx, |buffer, cx| {
17141                    if let Some(transaction) = transaction
17142                        && !buffer.is_singleton()
17143                    {
17144                        buffer.push_transaction(&transaction.0, cx);
17145                    }
17146                    cx.notify();
17147                })
17148                .ok();
17149
17150            if let Some(transaction_id_now) =
17151                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17152            {
17153                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17154                if has_new_transaction {
17155                    _ = editor.update(cx, |editor, _| {
17156                        editor
17157                            .selection_history
17158                            .insert_transaction(transaction_id_now, selections_prev);
17159                    });
17160                }
17161            }
17162
17163            Ok(())
17164        })
17165    }
17166
17167    fn organize_imports(
17168        &mut self,
17169        _: &OrganizeImports,
17170        window: &mut Window,
17171        cx: &mut Context<Self>,
17172    ) -> Option<Task<Result<()>>> {
17173        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17174        let project = match &self.project {
17175            Some(project) => project.clone(),
17176            None => return None,
17177        };
17178        Some(self.perform_code_action_kind(
17179            project,
17180            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17181            window,
17182            cx,
17183        ))
17184    }
17185
17186    fn perform_code_action_kind(
17187        &mut self,
17188        project: Entity<Project>,
17189        kind: CodeActionKind,
17190        window: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) -> Task<Result<()>> {
17193        let buffer = self.buffer.clone();
17194        let buffers = buffer.read(cx).all_buffers();
17195        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17196        let apply_action = project.update(cx, |project, cx| {
17197            project.apply_code_action_kind(buffers, kind, true, cx)
17198        });
17199        cx.spawn_in(window, async move |_, cx| {
17200            let transaction = futures::select_biased! {
17201                () = timeout => {
17202                    log::warn!("timed out waiting for executing code action");
17203                    None
17204                }
17205                transaction = apply_action.log_err().fuse() => transaction,
17206            };
17207            buffer
17208                .update(cx, |buffer, cx| {
17209                    // check if we need this
17210                    if let Some(transaction) = transaction
17211                        && !buffer.is_singleton()
17212                    {
17213                        buffer.push_transaction(&transaction.0, cx);
17214                    }
17215                    cx.notify();
17216                })
17217                .ok();
17218            Ok(())
17219        })
17220    }
17221
17222    pub fn restart_language_server(
17223        &mut self,
17224        _: &RestartLanguageServer,
17225        _: &mut Window,
17226        cx: &mut Context<Self>,
17227    ) {
17228        if let Some(project) = self.project.clone() {
17229            self.buffer.update(cx, |multi_buffer, cx| {
17230                project.update(cx, |project, cx| {
17231                    project.restart_language_servers_for_buffers(
17232                        multi_buffer.all_buffers().into_iter().collect(),
17233                        HashSet::default(),
17234                        cx,
17235                    );
17236                });
17237            })
17238        }
17239    }
17240
17241    pub fn stop_language_server(
17242        &mut self,
17243        _: &StopLanguageServer,
17244        _: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) {
17247        if let Some(project) = self.project.clone() {
17248            self.buffer.update(cx, |multi_buffer, cx| {
17249                project.update(cx, |project, cx| {
17250                    project.stop_language_servers_for_buffers(
17251                        multi_buffer.all_buffers().into_iter().collect(),
17252                        HashSet::default(),
17253                        cx,
17254                    );
17255                    cx.emit(project::Event::RefreshInlayHints);
17256                });
17257            });
17258        }
17259    }
17260
17261    fn cancel_language_server_work(
17262        workspace: &mut Workspace,
17263        _: &actions::CancelLanguageServerWork,
17264        _: &mut Window,
17265        cx: &mut Context<Workspace>,
17266    ) {
17267        let project = workspace.project();
17268        let buffers = workspace
17269            .active_item(cx)
17270            .and_then(|item| item.act_as::<Editor>(cx))
17271            .map_or(HashSet::default(), |editor| {
17272                editor.read(cx).buffer.read(cx).all_buffers()
17273            });
17274        project.update(cx, |project, cx| {
17275            project.cancel_language_server_work_for_buffers(buffers, cx);
17276        });
17277    }
17278
17279    fn show_character_palette(
17280        &mut self,
17281        _: &ShowCharacterPalette,
17282        window: &mut Window,
17283        _: &mut Context<Self>,
17284    ) {
17285        window.show_character_palette();
17286    }
17287
17288    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17289        if !self.diagnostics_enabled() {
17290            return;
17291        }
17292
17293        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17294            let buffer = self.buffer.read(cx).snapshot(cx);
17295            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17296            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17297            let is_valid = buffer
17298                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17299                .any(|entry| {
17300                    entry.diagnostic.is_primary
17301                        && !entry.range.is_empty()
17302                        && entry.range.start == primary_range_start
17303                        && entry.diagnostic.message == active_diagnostics.active_message
17304                });
17305
17306            if !is_valid {
17307                self.dismiss_diagnostics(cx);
17308            }
17309        }
17310    }
17311
17312    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17313        match &self.active_diagnostics {
17314            ActiveDiagnostic::Group(group) => Some(group),
17315            _ => None,
17316        }
17317    }
17318
17319    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17320        if !self.diagnostics_enabled() {
17321            return;
17322        }
17323        self.dismiss_diagnostics(cx);
17324        self.active_diagnostics = ActiveDiagnostic::All;
17325    }
17326
17327    fn activate_diagnostics(
17328        &mut self,
17329        buffer_id: BufferId,
17330        diagnostic: DiagnosticEntry<usize>,
17331        window: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) {
17334        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17335            return;
17336        }
17337        self.dismiss_diagnostics(cx);
17338        let snapshot = self.snapshot(window, cx);
17339        let buffer = self.buffer.read(cx).snapshot(cx);
17340        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17341            return;
17342        };
17343
17344        let diagnostic_group = buffer
17345            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17346            .collect::<Vec<_>>();
17347
17348        let blocks =
17349            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17350
17351        let blocks = self.display_map.update(cx, |display_map, cx| {
17352            display_map.insert_blocks(blocks, cx).into_iter().collect()
17353        });
17354        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17355            active_range: buffer.anchor_before(diagnostic.range.start)
17356                ..buffer.anchor_after(diagnostic.range.end),
17357            active_message: diagnostic.diagnostic.message.clone(),
17358            group_id: diagnostic.diagnostic.group_id,
17359            blocks,
17360        });
17361        cx.notify();
17362    }
17363
17364    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17365        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17366            return;
17367        };
17368
17369        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17370        if let ActiveDiagnostic::Group(group) = prev {
17371            self.display_map.update(cx, |display_map, cx| {
17372                display_map.remove_blocks(group.blocks, cx);
17373            });
17374            cx.notify();
17375        }
17376    }
17377
17378    /// Disable inline diagnostics rendering for this editor.
17379    pub fn disable_inline_diagnostics(&mut self) {
17380        self.inline_diagnostics_enabled = false;
17381        self.inline_diagnostics_update = Task::ready(());
17382        self.inline_diagnostics.clear();
17383    }
17384
17385    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17386        self.diagnostics_enabled = false;
17387        self.dismiss_diagnostics(cx);
17388        self.inline_diagnostics_update = Task::ready(());
17389        self.inline_diagnostics.clear();
17390    }
17391
17392    pub fn disable_word_completions(&mut self) {
17393        self.word_completions_enabled = false;
17394    }
17395
17396    pub fn diagnostics_enabled(&self) -> bool {
17397        self.diagnostics_enabled && self.mode.is_full()
17398    }
17399
17400    pub fn inline_diagnostics_enabled(&self) -> bool {
17401        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17402    }
17403
17404    pub fn show_inline_diagnostics(&self) -> bool {
17405        self.show_inline_diagnostics
17406    }
17407
17408    pub fn toggle_inline_diagnostics(
17409        &mut self,
17410        _: &ToggleInlineDiagnostics,
17411        window: &mut Window,
17412        cx: &mut Context<Editor>,
17413    ) {
17414        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17415        self.refresh_inline_diagnostics(false, window, cx);
17416    }
17417
17418    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17419        self.diagnostics_max_severity = severity;
17420        self.display_map.update(cx, |display_map, _| {
17421            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17422        });
17423    }
17424
17425    pub fn toggle_diagnostics(
17426        &mut self,
17427        _: &ToggleDiagnostics,
17428        window: &mut Window,
17429        cx: &mut Context<Editor>,
17430    ) {
17431        if !self.diagnostics_enabled() {
17432            return;
17433        }
17434
17435        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17436            EditorSettings::get_global(cx)
17437                .diagnostics_max_severity
17438                .filter(|severity| severity != &DiagnosticSeverity::Off)
17439                .unwrap_or(DiagnosticSeverity::Hint)
17440        } else {
17441            DiagnosticSeverity::Off
17442        };
17443        self.set_max_diagnostics_severity(new_severity, cx);
17444        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17445            self.active_diagnostics = ActiveDiagnostic::None;
17446            self.inline_diagnostics_update = Task::ready(());
17447            self.inline_diagnostics.clear();
17448        } else {
17449            self.refresh_inline_diagnostics(false, window, cx);
17450        }
17451
17452        cx.notify();
17453    }
17454
17455    pub fn toggle_minimap(
17456        &mut self,
17457        _: &ToggleMinimap,
17458        window: &mut Window,
17459        cx: &mut Context<Editor>,
17460    ) {
17461        if self.supports_minimap(cx) {
17462            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17463        }
17464    }
17465
17466    fn refresh_inline_diagnostics(
17467        &mut self,
17468        debounce: bool,
17469        window: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        let max_severity = ProjectSettings::get_global(cx)
17473            .diagnostics
17474            .inline
17475            .max_severity
17476            .unwrap_or(self.diagnostics_max_severity);
17477
17478        if !self.inline_diagnostics_enabled()
17479            || !self.show_inline_diagnostics
17480            || max_severity == DiagnosticSeverity::Off
17481        {
17482            self.inline_diagnostics_update = Task::ready(());
17483            self.inline_diagnostics.clear();
17484            return;
17485        }
17486
17487        let debounce_ms = ProjectSettings::get_global(cx)
17488            .diagnostics
17489            .inline
17490            .update_debounce_ms;
17491        let debounce = if debounce && debounce_ms > 0 {
17492            Some(Duration::from_millis(debounce_ms))
17493        } else {
17494            None
17495        };
17496        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17497            if let Some(debounce) = debounce {
17498                cx.background_executor().timer(debounce).await;
17499            }
17500            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17501                editor
17502                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17503                    .ok()
17504            }) else {
17505                return;
17506            };
17507
17508            let new_inline_diagnostics = cx
17509                .background_spawn(async move {
17510                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17511                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17512                        let message = diagnostic_entry
17513                            .diagnostic
17514                            .message
17515                            .split_once('\n')
17516                            .map(|(line, _)| line)
17517                            .map(SharedString::new)
17518                            .unwrap_or_else(|| {
17519                                SharedString::from(diagnostic_entry.diagnostic.message)
17520                            });
17521                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17522                        let (Ok(i) | Err(i)) = inline_diagnostics
17523                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17524                        inline_diagnostics.insert(
17525                            i,
17526                            (
17527                                start_anchor,
17528                                InlineDiagnostic {
17529                                    message,
17530                                    group_id: diagnostic_entry.diagnostic.group_id,
17531                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17532                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17533                                    severity: diagnostic_entry.diagnostic.severity,
17534                                },
17535                            ),
17536                        );
17537                    }
17538                    inline_diagnostics
17539                })
17540                .await;
17541
17542            editor
17543                .update(cx, |editor, cx| {
17544                    editor.inline_diagnostics = new_inline_diagnostics;
17545                    cx.notify();
17546                })
17547                .ok();
17548        });
17549    }
17550
17551    fn pull_diagnostics(
17552        &mut self,
17553        buffer_id: Option<BufferId>,
17554        window: &Window,
17555        cx: &mut Context<Self>,
17556    ) -> Option<()> {
17557        if !self.mode().is_full() {
17558            return None;
17559        }
17560        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17561            .diagnostics
17562            .lsp_pull_diagnostics;
17563        if !pull_diagnostics_settings.enabled {
17564            return None;
17565        }
17566        let project = self.project()?.downgrade();
17567        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17568        let mut buffers = self.buffer.read(cx).all_buffers();
17569        if let Some(buffer_id) = buffer_id {
17570            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17571        }
17572
17573        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17574            cx.background_executor().timer(debounce).await;
17575
17576            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17577                buffers
17578                    .into_iter()
17579                    .filter_map(|buffer| {
17580                        project
17581                            .update(cx, |project, cx| {
17582                                project.lsp_store().update(cx, |lsp_store, cx| {
17583                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17584                                })
17585                            })
17586                            .ok()
17587                    })
17588                    .collect::<FuturesUnordered<_>>()
17589            }) else {
17590                return;
17591            };
17592
17593            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17594                match pull_task {
17595                    Ok(()) => {
17596                        if editor
17597                            .update_in(cx, |editor, window, cx| {
17598                                editor.update_diagnostics_state(window, cx);
17599                            })
17600                            .is_err()
17601                        {
17602                            return;
17603                        }
17604                    }
17605                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17606                }
17607            }
17608        });
17609
17610        Some(())
17611    }
17612
17613    pub fn set_selections_from_remote(
17614        &mut self,
17615        selections: Vec<Selection<Anchor>>,
17616        pending_selection: Option<Selection<Anchor>>,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        let old_cursor_position = self.selections.newest_anchor().head();
17621        self.selections.change_with(cx, |s| {
17622            s.select_anchors(selections);
17623            if let Some(pending_selection) = pending_selection {
17624                s.set_pending(pending_selection, SelectMode::Character);
17625            } else {
17626                s.clear_pending();
17627            }
17628        });
17629        self.selections_did_change(
17630            false,
17631            &old_cursor_position,
17632            SelectionEffects::default(),
17633            window,
17634            cx,
17635        );
17636    }
17637
17638    pub fn transact(
17639        &mut self,
17640        window: &mut Window,
17641        cx: &mut Context<Self>,
17642        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17643    ) -> Option<TransactionId> {
17644        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17645            this.start_transaction_at(Instant::now(), window, cx);
17646            update(this, window, cx);
17647            this.end_transaction_at(Instant::now(), cx)
17648        })
17649    }
17650
17651    pub fn start_transaction_at(
17652        &mut self,
17653        now: Instant,
17654        window: &mut Window,
17655        cx: &mut Context<Self>,
17656    ) -> Option<TransactionId> {
17657        self.end_selection(window, cx);
17658        if let Some(tx_id) = self
17659            .buffer
17660            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17661        {
17662            self.selection_history
17663                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17664            cx.emit(EditorEvent::TransactionBegun {
17665                transaction_id: tx_id,
17666            });
17667            Some(tx_id)
17668        } else {
17669            None
17670        }
17671    }
17672
17673    pub fn end_transaction_at(
17674        &mut self,
17675        now: Instant,
17676        cx: &mut Context<Self>,
17677    ) -> Option<TransactionId> {
17678        if let Some(transaction_id) = self
17679            .buffer
17680            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17681        {
17682            if let Some((_, end_selections)) =
17683                self.selection_history.transaction_mut(transaction_id)
17684            {
17685                *end_selections = Some(self.selections.disjoint_anchors());
17686            } else {
17687                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17688            }
17689
17690            cx.emit(EditorEvent::Edited { transaction_id });
17691            Some(transaction_id)
17692        } else {
17693            None
17694        }
17695    }
17696
17697    pub fn modify_transaction_selection_history(
17698        &mut self,
17699        transaction_id: TransactionId,
17700        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17701    ) -> bool {
17702        self.selection_history
17703            .transaction_mut(transaction_id)
17704            .map(modify)
17705            .is_some()
17706    }
17707
17708    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17709        if self.selection_mark_mode {
17710            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17711                s.move_with(|_, sel| {
17712                    sel.collapse_to(sel.head(), SelectionGoal::None);
17713                });
17714            })
17715        }
17716        self.selection_mark_mode = true;
17717        cx.notify();
17718    }
17719
17720    pub fn swap_selection_ends(
17721        &mut self,
17722        _: &actions::SwapSelectionEnds,
17723        window: &mut Window,
17724        cx: &mut Context<Self>,
17725    ) {
17726        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17727            s.move_with(|_, sel| {
17728                if sel.start != sel.end {
17729                    sel.reversed = !sel.reversed
17730                }
17731            });
17732        });
17733        self.request_autoscroll(Autoscroll::newest(), cx);
17734        cx.notify();
17735    }
17736
17737    pub fn toggle_focus(
17738        workspace: &mut Workspace,
17739        _: &actions::ToggleFocus,
17740        window: &mut Window,
17741        cx: &mut Context<Workspace>,
17742    ) {
17743        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17744            return;
17745        };
17746        workspace.activate_item(&item, true, true, window, cx);
17747    }
17748
17749    pub fn toggle_fold(
17750        &mut self,
17751        _: &actions::ToggleFold,
17752        window: &mut Window,
17753        cx: &mut Context<Self>,
17754    ) {
17755        if self.is_singleton(cx) {
17756            let selection = self.selections.newest::<Point>(cx);
17757
17758            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17759            let range = if selection.is_empty() {
17760                let point = selection.head().to_display_point(&display_map);
17761                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17762                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17763                    .to_point(&display_map);
17764                start..end
17765            } else {
17766                selection.range()
17767            };
17768            if display_map.folds_in_range(range).next().is_some() {
17769                self.unfold_lines(&Default::default(), window, cx)
17770            } else {
17771                self.fold(&Default::default(), window, cx)
17772            }
17773        } else {
17774            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17775            let buffer_ids: HashSet<_> = self
17776                .selections
17777                .disjoint_anchor_ranges()
17778                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17779                .collect();
17780
17781            let should_unfold = buffer_ids
17782                .iter()
17783                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17784
17785            for buffer_id in buffer_ids {
17786                if should_unfold {
17787                    self.unfold_buffer(buffer_id, cx);
17788                } else {
17789                    self.fold_buffer(buffer_id, cx);
17790                }
17791            }
17792        }
17793    }
17794
17795    pub fn toggle_fold_recursive(
17796        &mut self,
17797        _: &actions::ToggleFoldRecursive,
17798        window: &mut Window,
17799        cx: &mut Context<Self>,
17800    ) {
17801        let selection = self.selections.newest::<Point>(cx);
17802
17803        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17804        let range = if selection.is_empty() {
17805            let point = selection.head().to_display_point(&display_map);
17806            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17807            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17808                .to_point(&display_map);
17809            start..end
17810        } else {
17811            selection.range()
17812        };
17813        if display_map.folds_in_range(range).next().is_some() {
17814            self.unfold_recursive(&Default::default(), window, cx)
17815        } else {
17816            self.fold_recursive(&Default::default(), window, cx)
17817        }
17818    }
17819
17820    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17821        if self.is_singleton(cx) {
17822            let mut to_fold = Vec::new();
17823            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17824            let selections = self.selections.all_adjusted(cx);
17825
17826            for selection in selections {
17827                let range = selection.range().sorted();
17828                let buffer_start_row = range.start.row;
17829
17830                if range.start.row != range.end.row {
17831                    let mut found = false;
17832                    let mut row = range.start.row;
17833                    while row <= range.end.row {
17834                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17835                        {
17836                            found = true;
17837                            row = crease.range().end.row + 1;
17838                            to_fold.push(crease);
17839                        } else {
17840                            row += 1
17841                        }
17842                    }
17843                    if found {
17844                        continue;
17845                    }
17846                }
17847
17848                for row in (0..=range.start.row).rev() {
17849                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17850                        && crease.range().end.row >= buffer_start_row
17851                    {
17852                        to_fold.push(crease);
17853                        if row <= range.start.row {
17854                            break;
17855                        }
17856                    }
17857                }
17858            }
17859
17860            self.fold_creases(to_fold, true, window, cx);
17861        } else {
17862            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17863            let buffer_ids = self
17864                .selections
17865                .disjoint_anchor_ranges()
17866                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17867                .collect::<HashSet<_>>();
17868            for buffer_id in buffer_ids {
17869                self.fold_buffer(buffer_id, cx);
17870            }
17871        }
17872    }
17873
17874    pub fn toggle_fold_all(
17875        &mut self,
17876        _: &actions::ToggleFoldAll,
17877        window: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        if self.buffer.read(cx).is_singleton() {
17881            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17882            let has_folds = display_map
17883                .folds_in_range(0..display_map.buffer_snapshot.len())
17884                .next()
17885                .is_some();
17886
17887            if has_folds {
17888                self.unfold_all(&actions::UnfoldAll, window, cx);
17889            } else {
17890                self.fold_all(&actions::FoldAll, window, cx);
17891            }
17892        } else {
17893            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17894            let should_unfold = buffer_ids
17895                .iter()
17896                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17897
17898            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17899                editor
17900                    .update_in(cx, |editor, _, cx| {
17901                        for buffer_id in buffer_ids {
17902                            if should_unfold {
17903                                editor.unfold_buffer(buffer_id, cx);
17904                            } else {
17905                                editor.fold_buffer(buffer_id, cx);
17906                            }
17907                        }
17908                    })
17909                    .ok();
17910            });
17911        }
17912    }
17913
17914    fn fold_at_level(
17915        &mut self,
17916        fold_at: &FoldAtLevel,
17917        window: &mut Window,
17918        cx: &mut Context<Self>,
17919    ) {
17920        if !self.buffer.read(cx).is_singleton() {
17921            return;
17922        }
17923
17924        let fold_at_level = fold_at.0;
17925        let snapshot = self.buffer.read(cx).snapshot(cx);
17926        let mut to_fold = Vec::new();
17927        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17928
17929        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17930            while start_row < end_row {
17931                match self
17932                    .snapshot(window, cx)
17933                    .crease_for_buffer_row(MultiBufferRow(start_row))
17934                {
17935                    Some(crease) => {
17936                        let nested_start_row = crease.range().start.row + 1;
17937                        let nested_end_row = crease.range().end.row;
17938
17939                        if current_level < fold_at_level {
17940                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17941                        } else if current_level == fold_at_level {
17942                            to_fold.push(crease);
17943                        }
17944
17945                        start_row = nested_end_row + 1;
17946                    }
17947                    None => start_row += 1,
17948                }
17949            }
17950        }
17951
17952        self.fold_creases(to_fold, true, window, cx);
17953    }
17954
17955    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17956        if self.buffer.read(cx).is_singleton() {
17957            let mut fold_ranges = Vec::new();
17958            let snapshot = self.buffer.read(cx).snapshot(cx);
17959
17960            for row in 0..snapshot.max_row().0 {
17961                if let Some(foldable_range) = self
17962                    .snapshot(window, cx)
17963                    .crease_for_buffer_row(MultiBufferRow(row))
17964                {
17965                    fold_ranges.push(foldable_range);
17966                }
17967            }
17968
17969            self.fold_creases(fold_ranges, true, window, cx);
17970        } else {
17971            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17972                editor
17973                    .update_in(cx, |editor, _, cx| {
17974                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17975                            editor.fold_buffer(buffer_id, cx);
17976                        }
17977                    })
17978                    .ok();
17979            });
17980        }
17981    }
17982
17983    pub fn fold_function_bodies(
17984        &mut self,
17985        _: &actions::FoldFunctionBodies,
17986        window: &mut Window,
17987        cx: &mut Context<Self>,
17988    ) {
17989        let snapshot = self.buffer.read(cx).snapshot(cx);
17990
17991        let ranges = snapshot
17992            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17993            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17994            .collect::<Vec<_>>();
17995
17996        let creases = ranges
17997            .into_iter()
17998            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17999            .collect();
18000
18001        self.fold_creases(creases, true, window, cx);
18002    }
18003
18004    pub fn fold_recursive(
18005        &mut self,
18006        _: &actions::FoldRecursive,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        let mut to_fold = Vec::new();
18011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18012        let selections = self.selections.all_adjusted(cx);
18013
18014        for selection in selections {
18015            let range = selection.range().sorted();
18016            let buffer_start_row = range.start.row;
18017
18018            if range.start.row != range.end.row {
18019                let mut found = false;
18020                for row in range.start.row..=range.end.row {
18021                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18022                        found = true;
18023                        to_fold.push(crease);
18024                    }
18025                }
18026                if found {
18027                    continue;
18028                }
18029            }
18030
18031            for row in (0..=range.start.row).rev() {
18032                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18033                    if crease.range().end.row >= buffer_start_row {
18034                        to_fold.push(crease);
18035                    } else {
18036                        break;
18037                    }
18038                }
18039            }
18040        }
18041
18042        self.fold_creases(to_fold, true, window, cx);
18043    }
18044
18045    pub fn fold_at(
18046        &mut self,
18047        buffer_row: MultiBufferRow,
18048        window: &mut Window,
18049        cx: &mut Context<Self>,
18050    ) {
18051        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18052
18053        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18054            let autoscroll = self
18055                .selections
18056                .all::<Point>(cx)
18057                .iter()
18058                .any(|selection| crease.range().overlaps(&selection.range()));
18059
18060            self.fold_creases(vec![crease], autoscroll, window, cx);
18061        }
18062    }
18063
18064    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18065        if self.is_singleton(cx) {
18066            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18067            let buffer = &display_map.buffer_snapshot;
18068            let selections = self.selections.all::<Point>(cx);
18069            let ranges = selections
18070                .iter()
18071                .map(|s| {
18072                    let range = s.display_range(&display_map).sorted();
18073                    let mut start = range.start.to_point(&display_map);
18074                    let mut end = range.end.to_point(&display_map);
18075                    start.column = 0;
18076                    end.column = buffer.line_len(MultiBufferRow(end.row));
18077                    start..end
18078                })
18079                .collect::<Vec<_>>();
18080
18081            self.unfold_ranges(&ranges, true, true, cx);
18082        } else {
18083            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18084            let buffer_ids = self
18085                .selections
18086                .disjoint_anchor_ranges()
18087                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18088                .collect::<HashSet<_>>();
18089            for buffer_id in buffer_ids {
18090                self.unfold_buffer(buffer_id, cx);
18091            }
18092        }
18093    }
18094
18095    pub fn unfold_recursive(
18096        &mut self,
18097        _: &UnfoldRecursive,
18098        _window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18102        let selections = self.selections.all::<Point>(cx);
18103        let ranges = selections
18104            .iter()
18105            .map(|s| {
18106                let mut range = s.display_range(&display_map).sorted();
18107                *range.start.column_mut() = 0;
18108                *range.end.column_mut() = display_map.line_len(range.end.row());
18109                let start = range.start.to_point(&display_map);
18110                let end = range.end.to_point(&display_map);
18111                start..end
18112            })
18113            .collect::<Vec<_>>();
18114
18115        self.unfold_ranges(&ranges, true, true, cx);
18116    }
18117
18118    pub fn unfold_at(
18119        &mut self,
18120        buffer_row: MultiBufferRow,
18121        _window: &mut Window,
18122        cx: &mut Context<Self>,
18123    ) {
18124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18125
18126        let intersection_range = Point::new(buffer_row.0, 0)
18127            ..Point::new(
18128                buffer_row.0,
18129                display_map.buffer_snapshot.line_len(buffer_row),
18130            );
18131
18132        let autoscroll = self
18133            .selections
18134            .all::<Point>(cx)
18135            .iter()
18136            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18137
18138        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18139    }
18140
18141    pub fn unfold_all(
18142        &mut self,
18143        _: &actions::UnfoldAll,
18144        _window: &mut Window,
18145        cx: &mut Context<Self>,
18146    ) {
18147        if self.buffer.read(cx).is_singleton() {
18148            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18149            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18150        } else {
18151            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18152                editor
18153                    .update(cx, |editor, cx| {
18154                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18155                            editor.unfold_buffer(buffer_id, cx);
18156                        }
18157                    })
18158                    .ok();
18159            });
18160        }
18161    }
18162
18163    pub fn fold_selected_ranges(
18164        &mut self,
18165        _: &FoldSelectedRanges,
18166        window: &mut Window,
18167        cx: &mut Context<Self>,
18168    ) {
18169        let selections = self.selections.all_adjusted(cx);
18170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18171        let ranges = selections
18172            .into_iter()
18173            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18174            .collect::<Vec<_>>();
18175        self.fold_creases(ranges, true, window, cx);
18176    }
18177
18178    pub fn fold_ranges<T: ToOffset + Clone>(
18179        &mut self,
18180        ranges: Vec<Range<T>>,
18181        auto_scroll: bool,
18182        window: &mut Window,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18186        let ranges = ranges
18187            .into_iter()
18188            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18189            .collect::<Vec<_>>();
18190        self.fold_creases(ranges, auto_scroll, window, cx);
18191    }
18192
18193    pub fn fold_creases<T: ToOffset + Clone>(
18194        &mut self,
18195        creases: Vec<Crease<T>>,
18196        auto_scroll: bool,
18197        _window: &mut Window,
18198        cx: &mut Context<Self>,
18199    ) {
18200        if creases.is_empty() {
18201            return;
18202        }
18203
18204        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18205
18206        if auto_scroll {
18207            self.request_autoscroll(Autoscroll::fit(), cx);
18208        }
18209
18210        cx.notify();
18211
18212        self.scrollbar_marker_state.dirty = true;
18213        self.folds_did_change(cx);
18214    }
18215
18216    /// Removes any folds whose ranges intersect any of the given ranges.
18217    pub fn unfold_ranges<T: ToOffset + Clone>(
18218        &mut self,
18219        ranges: &[Range<T>],
18220        inclusive: bool,
18221        auto_scroll: bool,
18222        cx: &mut Context<Self>,
18223    ) {
18224        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18225            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18226        });
18227        self.folds_did_change(cx);
18228    }
18229
18230    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18231        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18232            return;
18233        }
18234        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18235        self.display_map.update(cx, |display_map, cx| {
18236            display_map.fold_buffers([buffer_id], cx)
18237        });
18238        cx.emit(EditorEvent::BufferFoldToggled {
18239            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18240            folded: true,
18241        });
18242        cx.notify();
18243    }
18244
18245    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18246        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18247            return;
18248        }
18249        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18250        self.display_map.update(cx, |display_map, cx| {
18251            display_map.unfold_buffers([buffer_id], cx);
18252        });
18253        cx.emit(EditorEvent::BufferFoldToggled {
18254            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18255            folded: false,
18256        });
18257        cx.notify();
18258    }
18259
18260    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18261        self.display_map.read(cx).is_buffer_folded(buffer)
18262    }
18263
18264    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18265        self.display_map.read(cx).folded_buffers()
18266    }
18267
18268    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18269        self.display_map.update(cx, |display_map, cx| {
18270            display_map.disable_header_for_buffer(buffer_id, cx);
18271        });
18272        cx.notify();
18273    }
18274
18275    /// Removes any folds with the given ranges.
18276    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18277        &mut self,
18278        ranges: &[Range<T>],
18279        type_id: TypeId,
18280        auto_scroll: bool,
18281        cx: &mut Context<Self>,
18282    ) {
18283        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18284            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18285        });
18286        self.folds_did_change(cx);
18287    }
18288
18289    fn remove_folds_with<T: ToOffset + Clone>(
18290        &mut self,
18291        ranges: &[Range<T>],
18292        auto_scroll: bool,
18293        cx: &mut Context<Self>,
18294        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18295    ) {
18296        if ranges.is_empty() {
18297            return;
18298        }
18299
18300        let mut buffers_affected = HashSet::default();
18301        let multi_buffer = self.buffer().read(cx);
18302        for range in ranges {
18303            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18304                buffers_affected.insert(buffer.read(cx).remote_id());
18305            };
18306        }
18307
18308        self.display_map.update(cx, update);
18309
18310        if auto_scroll {
18311            self.request_autoscroll(Autoscroll::fit(), cx);
18312        }
18313
18314        cx.notify();
18315        self.scrollbar_marker_state.dirty = true;
18316        self.active_indent_guides_state.dirty = true;
18317    }
18318
18319    pub fn update_renderer_widths(
18320        &mut self,
18321        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18322        cx: &mut Context<Self>,
18323    ) -> bool {
18324        self.display_map
18325            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18326    }
18327
18328    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18329        self.display_map.read(cx).fold_placeholder.clone()
18330    }
18331
18332    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18333        self.buffer.update(cx, |buffer, cx| {
18334            buffer.set_all_diff_hunks_expanded(cx);
18335        });
18336    }
18337
18338    pub fn expand_all_diff_hunks(
18339        &mut self,
18340        _: &ExpandAllDiffHunks,
18341        _window: &mut Window,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.buffer.update(cx, |buffer, cx| {
18345            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18346        });
18347    }
18348
18349    pub fn toggle_selected_diff_hunks(
18350        &mut self,
18351        _: &ToggleSelectedDiffHunks,
18352        _window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18356        self.toggle_diff_hunks_in_ranges(ranges, cx);
18357    }
18358
18359    pub fn diff_hunks_in_ranges<'a>(
18360        &'a self,
18361        ranges: &'a [Range<Anchor>],
18362        buffer: &'a MultiBufferSnapshot,
18363    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18364        ranges.iter().flat_map(move |range| {
18365            let end_excerpt_id = range.end.excerpt_id;
18366            let range = range.to_point(buffer);
18367            let mut peek_end = range.end;
18368            if range.end.row < buffer.max_row().0 {
18369                peek_end = Point::new(range.end.row + 1, 0);
18370            }
18371            buffer
18372                .diff_hunks_in_range(range.start..peek_end)
18373                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18374        })
18375    }
18376
18377    pub fn has_stageable_diff_hunks_in_ranges(
18378        &self,
18379        ranges: &[Range<Anchor>],
18380        snapshot: &MultiBufferSnapshot,
18381    ) -> bool {
18382        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18383        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18384    }
18385
18386    pub fn toggle_staged_selected_diff_hunks(
18387        &mut self,
18388        _: &::git::ToggleStaged,
18389        _: &mut Window,
18390        cx: &mut Context<Self>,
18391    ) {
18392        let snapshot = self.buffer.read(cx).snapshot(cx);
18393        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18394        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18395        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18396    }
18397
18398    pub fn set_render_diff_hunk_controls(
18399        &mut self,
18400        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18401        cx: &mut Context<Self>,
18402    ) {
18403        self.render_diff_hunk_controls = render_diff_hunk_controls;
18404        cx.notify();
18405    }
18406
18407    pub fn stage_and_next(
18408        &mut self,
18409        _: &::git::StageAndNext,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412    ) {
18413        self.do_stage_or_unstage_and_next(true, window, cx);
18414    }
18415
18416    pub fn unstage_and_next(
18417        &mut self,
18418        _: &::git::UnstageAndNext,
18419        window: &mut Window,
18420        cx: &mut Context<Self>,
18421    ) {
18422        self.do_stage_or_unstage_and_next(false, window, cx);
18423    }
18424
18425    pub fn stage_or_unstage_diff_hunks(
18426        &mut self,
18427        stage: bool,
18428        ranges: Vec<Range<Anchor>>,
18429        cx: &mut Context<Self>,
18430    ) {
18431        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18432        cx.spawn(async move |this, cx| {
18433            task.await?;
18434            this.update(cx, |this, cx| {
18435                let snapshot = this.buffer.read(cx).snapshot(cx);
18436                let chunk_by = this
18437                    .diff_hunks_in_ranges(&ranges, &snapshot)
18438                    .chunk_by(|hunk| hunk.buffer_id);
18439                for (buffer_id, hunks) in &chunk_by {
18440                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18441                }
18442            })
18443        })
18444        .detach_and_log_err(cx);
18445    }
18446
18447    fn save_buffers_for_ranges_if_needed(
18448        &mut self,
18449        ranges: &[Range<Anchor>],
18450        cx: &mut Context<Editor>,
18451    ) -> Task<Result<()>> {
18452        let multibuffer = self.buffer.read(cx);
18453        let snapshot = multibuffer.read(cx);
18454        let buffer_ids: HashSet<_> = ranges
18455            .iter()
18456            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18457            .collect();
18458        drop(snapshot);
18459
18460        let mut buffers = HashSet::default();
18461        for buffer_id in buffer_ids {
18462            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18463                let buffer = buffer_entity.read(cx);
18464                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18465                {
18466                    buffers.insert(buffer_entity);
18467                }
18468            }
18469        }
18470
18471        if let Some(project) = &self.project {
18472            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18473        } else {
18474            Task::ready(Ok(()))
18475        }
18476    }
18477
18478    fn do_stage_or_unstage_and_next(
18479        &mut self,
18480        stage: bool,
18481        window: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18485
18486        if ranges.iter().any(|range| range.start != range.end) {
18487            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18488            return;
18489        }
18490
18491        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18492        let snapshot = self.snapshot(window, cx);
18493        let position = self.selections.newest::<Point>(cx).head();
18494        let mut row = snapshot
18495            .buffer_snapshot
18496            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18497            .find(|hunk| hunk.row_range.start.0 > position.row)
18498            .map(|hunk| hunk.row_range.start);
18499
18500        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18501        // Outside of the project diff editor, wrap around to the beginning.
18502        if !all_diff_hunks_expanded {
18503            row = row.or_else(|| {
18504                snapshot
18505                    .buffer_snapshot
18506                    .diff_hunks_in_range(Point::zero()..position)
18507                    .find(|hunk| hunk.row_range.end.0 < position.row)
18508                    .map(|hunk| hunk.row_range.start)
18509            });
18510        }
18511
18512        if let Some(row) = row {
18513            let destination = Point::new(row.0, 0);
18514            let autoscroll = Autoscroll::center();
18515
18516            self.unfold_ranges(&[destination..destination], false, false, cx);
18517            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18518                s.select_ranges([destination..destination]);
18519            });
18520        }
18521    }
18522
18523    fn do_stage_or_unstage(
18524        &self,
18525        stage: bool,
18526        buffer_id: BufferId,
18527        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18528        cx: &mut App,
18529    ) -> Option<()> {
18530        let project = self.project()?;
18531        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18532        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18533        let buffer_snapshot = buffer.read(cx).snapshot();
18534        let file_exists = buffer_snapshot
18535            .file()
18536            .is_some_and(|file| file.disk_state().exists());
18537        diff.update(cx, |diff, cx| {
18538            diff.stage_or_unstage_hunks(
18539                stage,
18540                &hunks
18541                    .map(|hunk| buffer_diff::DiffHunk {
18542                        buffer_range: hunk.buffer_range,
18543                        diff_base_byte_range: hunk.diff_base_byte_range,
18544                        secondary_status: hunk.secondary_status,
18545                        range: Point::zero()..Point::zero(), // unused
18546                    })
18547                    .collect::<Vec<_>>(),
18548                &buffer_snapshot,
18549                file_exists,
18550                cx,
18551            )
18552        });
18553        None
18554    }
18555
18556    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18557        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18558        self.buffer
18559            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18560    }
18561
18562    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18563        self.buffer.update(cx, |buffer, cx| {
18564            let ranges = vec![Anchor::min()..Anchor::max()];
18565            if !buffer.all_diff_hunks_expanded()
18566                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18567            {
18568                buffer.collapse_diff_hunks(ranges, cx);
18569                true
18570            } else {
18571                false
18572            }
18573        })
18574    }
18575
18576    fn toggle_diff_hunks_in_ranges(
18577        &mut self,
18578        ranges: Vec<Range<Anchor>>,
18579        cx: &mut Context<Editor>,
18580    ) {
18581        self.buffer.update(cx, |buffer, cx| {
18582            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18583            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18584        })
18585    }
18586
18587    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18588        self.buffer.update(cx, |buffer, cx| {
18589            let snapshot = buffer.snapshot(cx);
18590            let excerpt_id = range.end.excerpt_id;
18591            let point_range = range.to_point(&snapshot);
18592            let expand = !buffer.single_hunk_is_expanded(range, cx);
18593            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18594        })
18595    }
18596
18597    pub(crate) fn apply_all_diff_hunks(
18598        &mut self,
18599        _: &ApplyAllDiffHunks,
18600        window: &mut Window,
18601        cx: &mut Context<Self>,
18602    ) {
18603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18604
18605        let buffers = self.buffer.read(cx).all_buffers();
18606        for branch_buffer in buffers {
18607            branch_buffer.update(cx, |branch_buffer, cx| {
18608                branch_buffer.merge_into_base(Vec::new(), cx);
18609            });
18610        }
18611
18612        if let Some(project) = self.project.clone() {
18613            self.save(
18614                SaveOptions {
18615                    format: true,
18616                    autosave: false,
18617                },
18618                project,
18619                window,
18620                cx,
18621            )
18622            .detach_and_log_err(cx);
18623        }
18624    }
18625
18626    pub(crate) fn apply_selected_diff_hunks(
18627        &mut self,
18628        _: &ApplyDiffHunk,
18629        window: &mut Window,
18630        cx: &mut Context<Self>,
18631    ) {
18632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18633        let snapshot = self.snapshot(window, cx);
18634        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18635        let mut ranges_by_buffer = HashMap::default();
18636        self.transact(window, cx, |editor, _window, cx| {
18637            for hunk in hunks {
18638                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18639                    ranges_by_buffer
18640                        .entry(buffer.clone())
18641                        .or_insert_with(Vec::new)
18642                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18643                }
18644            }
18645
18646            for (buffer, ranges) in ranges_by_buffer {
18647                buffer.update(cx, |buffer, cx| {
18648                    buffer.merge_into_base(ranges, cx);
18649                });
18650            }
18651        });
18652
18653        if let Some(project) = self.project.clone() {
18654            self.save(
18655                SaveOptions {
18656                    format: true,
18657                    autosave: false,
18658                },
18659                project,
18660                window,
18661                cx,
18662            )
18663            .detach_and_log_err(cx);
18664        }
18665    }
18666
18667    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18668        if hovered != self.gutter_hovered {
18669            self.gutter_hovered = hovered;
18670            cx.notify();
18671        }
18672    }
18673
18674    pub fn insert_blocks(
18675        &mut self,
18676        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18677        autoscroll: Option<Autoscroll>,
18678        cx: &mut Context<Self>,
18679    ) -> Vec<CustomBlockId> {
18680        let blocks = self
18681            .display_map
18682            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18683        if let Some(autoscroll) = autoscroll {
18684            self.request_autoscroll(autoscroll, cx);
18685        }
18686        cx.notify();
18687        blocks
18688    }
18689
18690    pub fn resize_blocks(
18691        &mut self,
18692        heights: HashMap<CustomBlockId, u32>,
18693        autoscroll: Option<Autoscroll>,
18694        cx: &mut Context<Self>,
18695    ) {
18696        self.display_map
18697            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18698        if let Some(autoscroll) = autoscroll {
18699            self.request_autoscroll(autoscroll, cx);
18700        }
18701        cx.notify();
18702    }
18703
18704    pub fn replace_blocks(
18705        &mut self,
18706        renderers: HashMap<CustomBlockId, RenderBlock>,
18707        autoscroll: Option<Autoscroll>,
18708        cx: &mut Context<Self>,
18709    ) {
18710        self.display_map
18711            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18712        if let Some(autoscroll) = autoscroll {
18713            self.request_autoscroll(autoscroll, cx);
18714        }
18715        cx.notify();
18716    }
18717
18718    pub fn remove_blocks(
18719        &mut self,
18720        block_ids: HashSet<CustomBlockId>,
18721        autoscroll: Option<Autoscroll>,
18722        cx: &mut Context<Self>,
18723    ) {
18724        self.display_map.update(cx, |display_map, cx| {
18725            display_map.remove_blocks(block_ids, cx)
18726        });
18727        if let Some(autoscroll) = autoscroll {
18728            self.request_autoscroll(autoscroll, cx);
18729        }
18730        cx.notify();
18731    }
18732
18733    pub fn row_for_block(
18734        &self,
18735        block_id: CustomBlockId,
18736        cx: &mut Context<Self>,
18737    ) -> Option<DisplayRow> {
18738        self.display_map
18739            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18740    }
18741
18742    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18743        self.focused_block = Some(focused_block);
18744    }
18745
18746    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18747        self.focused_block.take()
18748    }
18749
18750    pub fn insert_creases(
18751        &mut self,
18752        creases: impl IntoIterator<Item = Crease<Anchor>>,
18753        cx: &mut Context<Self>,
18754    ) -> Vec<CreaseId> {
18755        self.display_map
18756            .update(cx, |map, cx| map.insert_creases(creases, cx))
18757    }
18758
18759    pub fn remove_creases(
18760        &mut self,
18761        ids: impl IntoIterator<Item = CreaseId>,
18762        cx: &mut Context<Self>,
18763    ) -> Vec<(CreaseId, Range<Anchor>)> {
18764        self.display_map
18765            .update(cx, |map, cx| map.remove_creases(ids, cx))
18766    }
18767
18768    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18769        self.display_map
18770            .update(cx, |map, cx| map.snapshot(cx))
18771            .longest_row()
18772    }
18773
18774    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18775        self.display_map
18776            .update(cx, |map, cx| map.snapshot(cx))
18777            .max_point()
18778    }
18779
18780    pub fn text(&self, cx: &App) -> String {
18781        self.buffer.read(cx).read(cx).text()
18782    }
18783
18784    pub fn is_empty(&self, cx: &App) -> bool {
18785        self.buffer.read(cx).read(cx).is_empty()
18786    }
18787
18788    pub fn text_option(&self, cx: &App) -> Option<String> {
18789        let text = self.text(cx);
18790        let text = text.trim();
18791
18792        if text.is_empty() {
18793            return None;
18794        }
18795
18796        Some(text.to_string())
18797    }
18798
18799    pub fn set_text(
18800        &mut self,
18801        text: impl Into<Arc<str>>,
18802        window: &mut Window,
18803        cx: &mut Context<Self>,
18804    ) {
18805        self.transact(window, cx, |this, _, cx| {
18806            this.buffer
18807                .read(cx)
18808                .as_singleton()
18809                .expect("you can only call set_text on editors for singleton buffers")
18810                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18811        });
18812    }
18813
18814    pub fn display_text(&self, cx: &mut App) -> String {
18815        self.display_map
18816            .update(cx, |map, cx| map.snapshot(cx))
18817            .text()
18818    }
18819
18820    fn create_minimap(
18821        &self,
18822        minimap_settings: MinimapSettings,
18823        window: &mut Window,
18824        cx: &mut Context<Self>,
18825    ) -> Option<Entity<Self>> {
18826        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18827            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18828    }
18829
18830    fn initialize_new_minimap(
18831        &self,
18832        minimap_settings: MinimapSettings,
18833        window: &mut Window,
18834        cx: &mut Context<Self>,
18835    ) -> Entity<Self> {
18836        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18837
18838        let mut minimap = Editor::new_internal(
18839            EditorMode::Minimap {
18840                parent: cx.weak_entity(),
18841            },
18842            self.buffer.clone(),
18843            None,
18844            Some(self.display_map.clone()),
18845            window,
18846            cx,
18847        );
18848        minimap.scroll_manager.clone_state(&self.scroll_manager);
18849        minimap.set_text_style_refinement(TextStyleRefinement {
18850            font_size: Some(MINIMAP_FONT_SIZE),
18851            font_weight: Some(MINIMAP_FONT_WEIGHT),
18852            ..Default::default()
18853        });
18854        minimap.update_minimap_configuration(minimap_settings, cx);
18855        cx.new(|_| minimap)
18856    }
18857
18858    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18859        let current_line_highlight = minimap_settings
18860            .current_line_highlight
18861            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18862        self.set_current_line_highlight(Some(current_line_highlight));
18863    }
18864
18865    pub fn minimap(&self) -> Option<&Entity<Self>> {
18866        self.minimap
18867            .as_ref()
18868            .filter(|_| self.minimap_visibility.visible())
18869    }
18870
18871    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18872        let mut wrap_guides = smallvec![];
18873
18874        if self.show_wrap_guides == Some(false) {
18875            return wrap_guides;
18876        }
18877
18878        let settings = self.buffer.read(cx).language_settings(cx);
18879        if settings.show_wrap_guides {
18880            match self.soft_wrap_mode(cx) {
18881                SoftWrap::Column(soft_wrap) => {
18882                    wrap_guides.push((soft_wrap as usize, true));
18883                }
18884                SoftWrap::Bounded(soft_wrap) => {
18885                    wrap_guides.push((soft_wrap as usize, true));
18886                }
18887                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18888            }
18889            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18890        }
18891
18892        wrap_guides
18893    }
18894
18895    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18896        let settings = self.buffer.read(cx).language_settings(cx);
18897        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18898        match mode {
18899            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18900                SoftWrap::None
18901            }
18902            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18903            language_settings::SoftWrap::PreferredLineLength => {
18904                SoftWrap::Column(settings.preferred_line_length)
18905            }
18906            language_settings::SoftWrap::Bounded => {
18907                SoftWrap::Bounded(settings.preferred_line_length)
18908            }
18909        }
18910    }
18911
18912    pub fn set_soft_wrap_mode(
18913        &mut self,
18914        mode: language_settings::SoftWrap,
18915
18916        cx: &mut Context<Self>,
18917    ) {
18918        self.soft_wrap_mode_override = Some(mode);
18919        cx.notify();
18920    }
18921
18922    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18923        self.hard_wrap = hard_wrap;
18924        cx.notify();
18925    }
18926
18927    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18928        self.text_style_refinement = Some(style);
18929    }
18930
18931    /// called by the Element so we know what style we were most recently rendered with.
18932    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18933        // We intentionally do not inform the display map about the minimap style
18934        // so that wrapping is not recalculated and stays consistent for the editor
18935        // and its linked minimap.
18936        if !self.mode.is_minimap() {
18937            let font = style.text.font();
18938            let font_size = style.text.font_size.to_pixels(window.rem_size());
18939            let display_map = self
18940                .placeholder_display_map
18941                .as_ref()
18942                .filter(|_| self.is_empty(cx))
18943                .unwrap_or(&self.display_map);
18944
18945            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18946        }
18947        self.style = Some(style);
18948    }
18949
18950    pub fn style(&self) -> Option<&EditorStyle> {
18951        self.style.as_ref()
18952    }
18953
18954    // Called by the element. This method is not designed to be called outside of the editor
18955    // element's layout code because it does not notify when rewrapping is computed synchronously.
18956    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18957        if self.is_empty(cx) {
18958            self.placeholder_display_map
18959                .as_ref()
18960                .map_or(false, |display_map| {
18961                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18962                })
18963        } else {
18964            self.display_map
18965                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18966        }
18967    }
18968
18969    pub fn set_soft_wrap(&mut self) {
18970        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18971    }
18972
18973    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18974        if self.soft_wrap_mode_override.is_some() {
18975            self.soft_wrap_mode_override.take();
18976        } else {
18977            let soft_wrap = match self.soft_wrap_mode(cx) {
18978                SoftWrap::GitDiff => return,
18979                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18980                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18981                    language_settings::SoftWrap::None
18982                }
18983            };
18984            self.soft_wrap_mode_override = Some(soft_wrap);
18985        }
18986        cx.notify();
18987    }
18988
18989    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18990        let Some(workspace) = self.workspace() else {
18991            return;
18992        };
18993        let fs = workspace.read(cx).app_state().fs.clone();
18994        let current_show = TabBarSettings::get_global(cx).show;
18995        update_settings_file(fs, cx, move |setting, _| {
18996            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
18997        });
18998    }
18999
19000    pub fn toggle_indent_guides(
19001        &mut self,
19002        _: &ToggleIndentGuides,
19003        _: &mut Window,
19004        cx: &mut Context<Self>,
19005    ) {
19006        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19007            self.buffer
19008                .read(cx)
19009                .language_settings(cx)
19010                .indent_guides
19011                .enabled
19012        });
19013        self.show_indent_guides = Some(!currently_enabled);
19014        cx.notify();
19015    }
19016
19017    fn should_show_indent_guides(&self) -> Option<bool> {
19018        self.show_indent_guides
19019    }
19020
19021    pub fn toggle_line_numbers(
19022        &mut self,
19023        _: &ToggleLineNumbers,
19024        _: &mut Window,
19025        cx: &mut Context<Self>,
19026    ) {
19027        let mut editor_settings = EditorSettings::get_global(cx).clone();
19028        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19029        EditorSettings::override_global(editor_settings, cx);
19030    }
19031
19032    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19033        if let Some(show_line_numbers) = self.show_line_numbers {
19034            return show_line_numbers;
19035        }
19036        EditorSettings::get_global(cx).gutter.line_numbers
19037    }
19038
19039    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19040        self.use_relative_line_numbers
19041            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19042    }
19043
19044    pub fn toggle_relative_line_numbers(
19045        &mut self,
19046        _: &ToggleRelativeLineNumbers,
19047        _: &mut Window,
19048        cx: &mut Context<Self>,
19049    ) {
19050        let is_relative = self.should_use_relative_line_numbers(cx);
19051        self.set_relative_line_number(Some(!is_relative), cx)
19052    }
19053
19054    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19055        self.use_relative_line_numbers = is_relative;
19056        cx.notify();
19057    }
19058
19059    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19060        self.show_gutter = show_gutter;
19061        cx.notify();
19062    }
19063
19064    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19065        self.show_scrollbars = ScrollbarAxes {
19066            horizontal: show,
19067            vertical: show,
19068        };
19069        cx.notify();
19070    }
19071
19072    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19073        self.show_scrollbars.vertical = show;
19074        cx.notify();
19075    }
19076
19077    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19078        self.show_scrollbars.horizontal = show;
19079        cx.notify();
19080    }
19081
19082    pub fn set_minimap_visibility(
19083        &mut self,
19084        minimap_visibility: MinimapVisibility,
19085        window: &mut Window,
19086        cx: &mut Context<Self>,
19087    ) {
19088        if self.minimap_visibility != minimap_visibility {
19089            if minimap_visibility.visible() && self.minimap.is_none() {
19090                let minimap_settings = EditorSettings::get_global(cx).minimap;
19091                self.minimap =
19092                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19093            }
19094            self.minimap_visibility = minimap_visibility;
19095            cx.notify();
19096        }
19097    }
19098
19099    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19100        self.set_show_scrollbars(false, cx);
19101        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19102    }
19103
19104    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19105        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19106    }
19107
19108    /// Normally the text in full mode and auto height editors is padded on the
19109    /// left side by roughly half a character width for improved hit testing.
19110    ///
19111    /// Use this method to disable this for cases where this is not wanted (e.g.
19112    /// if you want to align the editor text with some other text above or below)
19113    /// or if you want to add this padding to single-line editors.
19114    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19115        self.offset_content = offset_content;
19116        cx.notify();
19117    }
19118
19119    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19120        self.show_line_numbers = Some(show_line_numbers);
19121        cx.notify();
19122    }
19123
19124    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19125        self.disable_expand_excerpt_buttons = true;
19126        cx.notify();
19127    }
19128
19129    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19130        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19131        cx.notify();
19132    }
19133
19134    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19135        self.show_code_actions = Some(show_code_actions);
19136        cx.notify();
19137    }
19138
19139    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19140        self.show_runnables = Some(show_runnables);
19141        cx.notify();
19142    }
19143
19144    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19145        self.show_breakpoints = Some(show_breakpoints);
19146        cx.notify();
19147    }
19148
19149    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19150        if self.display_map.read(cx).masked != masked {
19151            self.display_map.update(cx, |map, _| map.masked = masked);
19152        }
19153        cx.notify()
19154    }
19155
19156    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19157        self.show_wrap_guides = Some(show_wrap_guides);
19158        cx.notify();
19159    }
19160
19161    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19162        self.show_indent_guides = Some(show_indent_guides);
19163        cx.notify();
19164    }
19165
19166    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19167        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19168            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19169                && let Some(dir) = file.abs_path(cx).parent()
19170            {
19171                return Some(dir.to_owned());
19172            }
19173
19174            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19175                return Some(project_path.path.to_path_buf());
19176            }
19177        }
19178
19179        None
19180    }
19181
19182    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19183        self.active_excerpt(cx)?
19184            .1
19185            .read(cx)
19186            .file()
19187            .and_then(|f| f.as_local())
19188    }
19189
19190    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19191        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19192            let buffer = buffer.read(cx);
19193            if let Some(project_path) = buffer.project_path(cx) {
19194                let project = self.project()?.read(cx);
19195                project.absolute_path(&project_path, cx)
19196            } else {
19197                buffer
19198                    .file()
19199                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19200            }
19201        })
19202    }
19203
19204    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19205        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19206            let project_path = buffer.read(cx).project_path(cx)?;
19207            let project = self.project()?.read(cx);
19208            let entry = project.entry_for_path(&project_path, cx)?;
19209            let path = entry.path.to_path_buf();
19210            Some(path)
19211        })
19212    }
19213
19214    pub fn reveal_in_finder(
19215        &mut self,
19216        _: &RevealInFileManager,
19217        _window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        if let Some(target) = self.target_file(cx) {
19221            cx.reveal_path(&target.abs_path(cx));
19222        }
19223    }
19224
19225    pub fn copy_path(
19226        &mut self,
19227        _: &zed_actions::workspace::CopyPath,
19228        _window: &mut Window,
19229        cx: &mut Context<Self>,
19230    ) {
19231        if let Some(path) = self.target_file_abs_path(cx)
19232            && let Some(path) = path.to_str()
19233        {
19234            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19235        }
19236    }
19237
19238    pub fn copy_relative_path(
19239        &mut self,
19240        _: &zed_actions::workspace::CopyRelativePath,
19241        _window: &mut Window,
19242        cx: &mut Context<Self>,
19243    ) {
19244        if let Some(path) = self.target_file_path(cx)
19245            && let Some(path) = path.to_str()
19246        {
19247            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19248        }
19249    }
19250
19251    /// Returns the project path for the editor's buffer, if any buffer is
19252    /// opened in the editor.
19253    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19254        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19255            buffer.read(cx).project_path(cx)
19256        } else {
19257            None
19258        }
19259    }
19260
19261    // Returns true if the editor handled a go-to-line request
19262    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19263        maybe!({
19264            let breakpoint_store = self.breakpoint_store.as_ref()?;
19265
19266            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19267            else {
19268                self.clear_row_highlights::<ActiveDebugLine>();
19269                return None;
19270            };
19271
19272            let position = active_stack_frame.position;
19273            let buffer_id = position.buffer_id?;
19274            let snapshot = self
19275                .project
19276                .as_ref()?
19277                .read(cx)
19278                .buffer_for_id(buffer_id, cx)?
19279                .read(cx)
19280                .snapshot();
19281
19282            let mut handled = false;
19283            for (id, ExcerptRange { context, .. }) in
19284                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19285            {
19286                if context.start.cmp(&position, &snapshot).is_ge()
19287                    || context.end.cmp(&position, &snapshot).is_lt()
19288                {
19289                    continue;
19290                }
19291                let snapshot = self.buffer.read(cx).snapshot(cx);
19292                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19293
19294                handled = true;
19295                self.clear_row_highlights::<ActiveDebugLine>();
19296
19297                self.go_to_line::<ActiveDebugLine>(
19298                    multibuffer_anchor,
19299                    Some(cx.theme().colors().editor_debugger_active_line_background),
19300                    window,
19301                    cx,
19302                );
19303
19304                cx.notify();
19305            }
19306
19307            handled.then_some(())
19308        })
19309        .is_some()
19310    }
19311
19312    pub fn copy_file_name_without_extension(
19313        &mut self,
19314        _: &CopyFileNameWithoutExtension,
19315        _: &mut Window,
19316        cx: &mut Context<Self>,
19317    ) {
19318        if let Some(file) = self.target_file(cx)
19319            && let Some(file_stem) = file.path().file_stem()
19320            && let Some(name) = file_stem.to_str()
19321        {
19322            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19323        }
19324    }
19325
19326    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19327        if let Some(file) = self.target_file(cx)
19328            && let Some(file_name) = file.path().file_name()
19329            && let Some(name) = file_name.to_str()
19330        {
19331            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19332        }
19333    }
19334
19335    pub fn toggle_git_blame(
19336        &mut self,
19337        _: &::git::Blame,
19338        window: &mut Window,
19339        cx: &mut Context<Self>,
19340    ) {
19341        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19342
19343        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19344            self.start_git_blame(true, window, cx);
19345        }
19346
19347        cx.notify();
19348    }
19349
19350    pub fn toggle_git_blame_inline(
19351        &mut self,
19352        _: &ToggleGitBlameInline,
19353        window: &mut Window,
19354        cx: &mut Context<Self>,
19355    ) {
19356        self.toggle_git_blame_inline_internal(true, window, cx);
19357        cx.notify();
19358    }
19359
19360    pub fn open_git_blame_commit(
19361        &mut self,
19362        _: &OpenGitBlameCommit,
19363        window: &mut Window,
19364        cx: &mut Context<Self>,
19365    ) {
19366        self.open_git_blame_commit_internal(window, cx);
19367    }
19368
19369    fn open_git_blame_commit_internal(
19370        &mut self,
19371        window: &mut Window,
19372        cx: &mut Context<Self>,
19373    ) -> Option<()> {
19374        let blame = self.blame.as_ref()?;
19375        let snapshot = self.snapshot(window, cx);
19376        let cursor = self.selections.newest::<Point>(cx).head();
19377        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19378        let (_, blame_entry) = blame
19379            .update(cx, |blame, cx| {
19380                blame
19381                    .blame_for_rows(
19382                        &[RowInfo {
19383                            buffer_id: Some(buffer.remote_id()),
19384                            buffer_row: Some(point.row),
19385                            ..Default::default()
19386                        }],
19387                        cx,
19388                    )
19389                    .next()
19390            })
19391            .flatten()?;
19392        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19393        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19394        let workspace = self.workspace()?.downgrade();
19395        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19396        None
19397    }
19398
19399    pub fn git_blame_inline_enabled(&self) -> bool {
19400        self.git_blame_inline_enabled
19401    }
19402
19403    pub fn toggle_selection_menu(
19404        &mut self,
19405        _: &ToggleSelectionMenu,
19406        _: &mut Window,
19407        cx: &mut Context<Self>,
19408    ) {
19409        self.show_selection_menu = self
19410            .show_selection_menu
19411            .map(|show_selections_menu| !show_selections_menu)
19412            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19413
19414        cx.notify();
19415    }
19416
19417    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19418        self.show_selection_menu
19419            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19420    }
19421
19422    fn start_git_blame(
19423        &mut self,
19424        user_triggered: bool,
19425        window: &mut Window,
19426        cx: &mut Context<Self>,
19427    ) {
19428        if let Some(project) = self.project() {
19429            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19430                && buffer.read(cx).file().is_none()
19431            {
19432                return;
19433            }
19434
19435            let focused = self.focus_handle(cx).contains_focused(window, cx);
19436
19437            let project = project.clone();
19438            let blame = cx
19439                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19440            self.blame_subscription =
19441                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19442            self.blame = Some(blame);
19443        }
19444    }
19445
19446    fn toggle_git_blame_inline_internal(
19447        &mut self,
19448        user_triggered: bool,
19449        window: &mut Window,
19450        cx: &mut Context<Self>,
19451    ) {
19452        if self.git_blame_inline_enabled {
19453            self.git_blame_inline_enabled = false;
19454            self.show_git_blame_inline = false;
19455            self.show_git_blame_inline_delay_task.take();
19456        } else {
19457            self.git_blame_inline_enabled = true;
19458            self.start_git_blame_inline(user_triggered, window, cx);
19459        }
19460
19461        cx.notify();
19462    }
19463
19464    fn start_git_blame_inline(
19465        &mut self,
19466        user_triggered: bool,
19467        window: &mut Window,
19468        cx: &mut Context<Self>,
19469    ) {
19470        self.start_git_blame(user_triggered, window, cx);
19471
19472        if ProjectSettings::get_global(cx)
19473            .git
19474            .inline_blame_delay()
19475            .is_some()
19476        {
19477            self.start_inline_blame_timer(window, cx);
19478        } else {
19479            self.show_git_blame_inline = true
19480        }
19481    }
19482
19483    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19484        self.blame.as_ref()
19485    }
19486
19487    pub fn show_git_blame_gutter(&self) -> bool {
19488        self.show_git_blame_gutter
19489    }
19490
19491    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19492        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19493    }
19494
19495    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19496        self.show_git_blame_inline
19497            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19498            && !self.newest_selection_head_on_empty_line(cx)
19499            && self.has_blame_entries(cx)
19500    }
19501
19502    fn has_blame_entries(&self, cx: &App) -> bool {
19503        self.blame()
19504            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19505    }
19506
19507    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19508        let cursor_anchor = self.selections.newest_anchor().head();
19509
19510        let snapshot = self.buffer.read(cx).snapshot(cx);
19511        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19512
19513        snapshot.line_len(buffer_row) == 0
19514    }
19515
19516    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19517        let buffer_and_selection = maybe!({
19518            let selection = self.selections.newest::<Point>(cx);
19519            let selection_range = selection.range();
19520
19521            let multi_buffer = self.buffer().read(cx);
19522            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19523            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19524
19525            let (buffer, range, _) = if selection.reversed {
19526                buffer_ranges.first()
19527            } else {
19528                buffer_ranges.last()
19529            }?;
19530
19531            let selection = text::ToPoint::to_point(&range.start, buffer).row
19532                ..text::ToPoint::to_point(&range.end, buffer).row;
19533            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19534        });
19535
19536        let Some((buffer, selection)) = buffer_and_selection else {
19537            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19538        };
19539
19540        let Some(project) = self.project() else {
19541            return Task::ready(Err(anyhow!("editor does not have project")));
19542        };
19543
19544        project.update(cx, |project, cx| {
19545            project.get_permalink_to_line(&buffer, selection, cx)
19546        })
19547    }
19548
19549    pub fn copy_permalink_to_line(
19550        &mut self,
19551        _: &CopyPermalinkToLine,
19552        window: &mut Window,
19553        cx: &mut Context<Self>,
19554    ) {
19555        let permalink_task = self.get_permalink_to_line(cx);
19556        let workspace = self.workspace();
19557
19558        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19559            Ok(permalink) => {
19560                cx.update(|_, cx| {
19561                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19562                })
19563                .ok();
19564            }
19565            Err(err) => {
19566                let message = format!("Failed to copy permalink: {err}");
19567
19568                anyhow::Result::<()>::Err(err).log_err();
19569
19570                if let Some(workspace) = workspace {
19571                    workspace
19572                        .update_in(cx, |workspace, _, cx| {
19573                            struct CopyPermalinkToLine;
19574
19575                            workspace.show_toast(
19576                                Toast::new(
19577                                    NotificationId::unique::<CopyPermalinkToLine>(),
19578                                    message,
19579                                ),
19580                                cx,
19581                            )
19582                        })
19583                        .ok();
19584                }
19585            }
19586        })
19587        .detach();
19588    }
19589
19590    pub fn copy_file_location(
19591        &mut self,
19592        _: &CopyFileLocation,
19593        _: &mut Window,
19594        cx: &mut Context<Self>,
19595    ) {
19596        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19597        if let Some(file) = self.target_file(cx)
19598            && let Some(path) = file.path().to_str()
19599        {
19600            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19601        }
19602    }
19603
19604    pub fn open_permalink_to_line(
19605        &mut self,
19606        _: &OpenPermalinkToLine,
19607        window: &mut Window,
19608        cx: &mut Context<Self>,
19609    ) {
19610        let permalink_task = self.get_permalink_to_line(cx);
19611        let workspace = self.workspace();
19612
19613        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19614            Ok(permalink) => {
19615                cx.update(|_, cx| {
19616                    cx.open_url(permalink.as_ref());
19617                })
19618                .ok();
19619            }
19620            Err(err) => {
19621                let message = format!("Failed to open permalink: {err}");
19622
19623                anyhow::Result::<()>::Err(err).log_err();
19624
19625                if let Some(workspace) = workspace {
19626                    workspace
19627                        .update(cx, |workspace, cx| {
19628                            struct OpenPermalinkToLine;
19629
19630                            workspace.show_toast(
19631                                Toast::new(
19632                                    NotificationId::unique::<OpenPermalinkToLine>(),
19633                                    message,
19634                                ),
19635                                cx,
19636                            )
19637                        })
19638                        .ok();
19639                }
19640            }
19641        })
19642        .detach();
19643    }
19644
19645    pub fn insert_uuid_v4(
19646        &mut self,
19647        _: &InsertUuidV4,
19648        window: &mut Window,
19649        cx: &mut Context<Self>,
19650    ) {
19651        self.insert_uuid(UuidVersion::V4, window, cx);
19652    }
19653
19654    pub fn insert_uuid_v7(
19655        &mut self,
19656        _: &InsertUuidV7,
19657        window: &mut Window,
19658        cx: &mut Context<Self>,
19659    ) {
19660        self.insert_uuid(UuidVersion::V7, window, cx);
19661    }
19662
19663    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19664        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19665        self.transact(window, cx, |this, window, cx| {
19666            let edits = this
19667                .selections
19668                .all::<Point>(cx)
19669                .into_iter()
19670                .map(|selection| {
19671                    let uuid = match version {
19672                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19673                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19674                    };
19675
19676                    (selection.range(), uuid.to_string())
19677                });
19678            this.edit(edits, cx);
19679            this.refresh_edit_prediction(true, false, window, cx);
19680        });
19681    }
19682
19683    pub fn open_selections_in_multibuffer(
19684        &mut self,
19685        _: &OpenSelectionsInMultibuffer,
19686        window: &mut Window,
19687        cx: &mut Context<Self>,
19688    ) {
19689        let multibuffer = self.buffer.read(cx);
19690
19691        let Some(buffer) = multibuffer.as_singleton() else {
19692            return;
19693        };
19694
19695        let Some(workspace) = self.workspace() else {
19696            return;
19697        };
19698
19699        let title = multibuffer.title(cx).to_string();
19700
19701        let locations = self
19702            .selections
19703            .all_anchors(cx)
19704            .iter()
19705            .map(|selection| Location {
19706                buffer: buffer.clone(),
19707                range: selection.start.text_anchor..selection.end.text_anchor,
19708            })
19709            .collect::<Vec<_>>();
19710
19711        cx.spawn_in(window, async move |_, cx| {
19712            workspace.update_in(cx, |workspace, window, cx| {
19713                Self::open_locations_in_multibuffer(
19714                    workspace,
19715                    locations,
19716                    format!("Selections for '{title}'"),
19717                    false,
19718                    MultibufferSelectionMode::All,
19719                    window,
19720                    cx,
19721                );
19722            })
19723        })
19724        .detach();
19725    }
19726
19727    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19728    /// last highlight added will be used.
19729    ///
19730    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19731    pub fn highlight_rows<T: 'static>(
19732        &mut self,
19733        range: Range<Anchor>,
19734        color: Hsla,
19735        options: RowHighlightOptions,
19736        cx: &mut Context<Self>,
19737    ) {
19738        let snapshot = self.buffer().read(cx).snapshot(cx);
19739        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19740        let ix = row_highlights.binary_search_by(|highlight| {
19741            Ordering::Equal
19742                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19743                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19744        });
19745
19746        if let Err(mut ix) = ix {
19747            let index = post_inc(&mut self.highlight_order);
19748
19749            // If this range intersects with the preceding highlight, then merge it with
19750            // the preceding highlight. Otherwise insert a new highlight.
19751            let mut merged = false;
19752            if ix > 0 {
19753                let prev_highlight = &mut row_highlights[ix - 1];
19754                if prev_highlight
19755                    .range
19756                    .end
19757                    .cmp(&range.start, &snapshot)
19758                    .is_ge()
19759                {
19760                    ix -= 1;
19761                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19762                        prev_highlight.range.end = range.end;
19763                    }
19764                    merged = true;
19765                    prev_highlight.index = index;
19766                    prev_highlight.color = color;
19767                    prev_highlight.options = options;
19768                }
19769            }
19770
19771            if !merged {
19772                row_highlights.insert(
19773                    ix,
19774                    RowHighlight {
19775                        range,
19776                        index,
19777                        color,
19778                        options,
19779                        type_id: TypeId::of::<T>(),
19780                    },
19781                );
19782            }
19783
19784            // If any of the following highlights intersect with this one, merge them.
19785            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19786                let highlight = &row_highlights[ix];
19787                if next_highlight
19788                    .range
19789                    .start
19790                    .cmp(&highlight.range.end, &snapshot)
19791                    .is_le()
19792                {
19793                    if next_highlight
19794                        .range
19795                        .end
19796                        .cmp(&highlight.range.end, &snapshot)
19797                        .is_gt()
19798                    {
19799                        row_highlights[ix].range.end = next_highlight.range.end;
19800                    }
19801                    row_highlights.remove(ix + 1);
19802                } else {
19803                    break;
19804                }
19805            }
19806        }
19807    }
19808
19809    /// Remove any highlighted row ranges of the given type that intersect the
19810    /// given ranges.
19811    pub fn remove_highlighted_rows<T: 'static>(
19812        &mut self,
19813        ranges_to_remove: Vec<Range<Anchor>>,
19814        cx: &mut Context<Self>,
19815    ) {
19816        let snapshot = self.buffer().read(cx).snapshot(cx);
19817        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19818        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19819        row_highlights.retain(|highlight| {
19820            while let Some(range_to_remove) = ranges_to_remove.peek() {
19821                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19822                    Ordering::Less | Ordering::Equal => {
19823                        ranges_to_remove.next();
19824                    }
19825                    Ordering::Greater => {
19826                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19827                            Ordering::Less | Ordering::Equal => {
19828                                return false;
19829                            }
19830                            Ordering::Greater => break,
19831                        }
19832                    }
19833                }
19834            }
19835
19836            true
19837        })
19838    }
19839
19840    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19841    pub fn clear_row_highlights<T: 'static>(&mut self) {
19842        self.highlighted_rows.remove(&TypeId::of::<T>());
19843    }
19844
19845    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19846    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19847        self.highlighted_rows
19848            .get(&TypeId::of::<T>())
19849            .map_or(&[] as &[_], |vec| vec.as_slice())
19850            .iter()
19851            .map(|highlight| (highlight.range.clone(), highlight.color))
19852    }
19853
19854    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19855    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19856    /// Allows to ignore certain kinds of highlights.
19857    pub fn highlighted_display_rows(
19858        &self,
19859        window: &mut Window,
19860        cx: &mut App,
19861    ) -> BTreeMap<DisplayRow, LineHighlight> {
19862        let snapshot = self.snapshot(window, cx);
19863        let mut used_highlight_orders = HashMap::default();
19864        self.highlighted_rows
19865            .iter()
19866            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19867            .fold(
19868                BTreeMap::<DisplayRow, LineHighlight>::new(),
19869                |mut unique_rows, highlight| {
19870                    let start = highlight.range.start.to_display_point(&snapshot);
19871                    let end = highlight.range.end.to_display_point(&snapshot);
19872                    let start_row = start.row().0;
19873                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19874                        && end.column() == 0
19875                    {
19876                        end.row().0.saturating_sub(1)
19877                    } else {
19878                        end.row().0
19879                    };
19880                    for row in start_row..=end_row {
19881                        let used_index =
19882                            used_highlight_orders.entry(row).or_insert(highlight.index);
19883                        if highlight.index >= *used_index {
19884                            *used_index = highlight.index;
19885                            unique_rows.insert(
19886                                DisplayRow(row),
19887                                LineHighlight {
19888                                    include_gutter: highlight.options.include_gutter,
19889                                    border: None,
19890                                    background: highlight.color.into(),
19891                                    type_id: Some(highlight.type_id),
19892                                },
19893                            );
19894                        }
19895                    }
19896                    unique_rows
19897                },
19898            )
19899    }
19900
19901    pub fn highlighted_display_row_for_autoscroll(
19902        &self,
19903        snapshot: &DisplaySnapshot,
19904    ) -> Option<DisplayRow> {
19905        self.highlighted_rows
19906            .values()
19907            .flat_map(|highlighted_rows| highlighted_rows.iter())
19908            .filter_map(|highlight| {
19909                if highlight.options.autoscroll {
19910                    Some(highlight.range.start.to_display_point(snapshot).row())
19911                } else {
19912                    None
19913                }
19914            })
19915            .min()
19916    }
19917
19918    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19919        self.highlight_background::<SearchWithinRange>(
19920            ranges,
19921            |colors| colors.colors().editor_document_highlight_read_background,
19922            cx,
19923        )
19924    }
19925
19926    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19927        self.breadcrumb_header = Some(new_header);
19928    }
19929
19930    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19931        self.clear_background_highlights::<SearchWithinRange>(cx);
19932    }
19933
19934    pub fn highlight_background<T: 'static>(
19935        &mut self,
19936        ranges: &[Range<Anchor>],
19937        color_fetcher: fn(&Theme) -> Hsla,
19938        cx: &mut Context<Self>,
19939    ) {
19940        self.background_highlights.insert(
19941            HighlightKey::Type(TypeId::of::<T>()),
19942            (color_fetcher, Arc::from(ranges)),
19943        );
19944        self.scrollbar_marker_state.dirty = true;
19945        cx.notify();
19946    }
19947
19948    pub fn highlight_background_key<T: 'static>(
19949        &mut self,
19950        key: usize,
19951        ranges: &[Range<Anchor>],
19952        color_fetcher: fn(&Theme) -> Hsla,
19953        cx: &mut Context<Self>,
19954    ) {
19955        self.background_highlights.insert(
19956            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19957            (color_fetcher, Arc::from(ranges)),
19958        );
19959        self.scrollbar_marker_state.dirty = true;
19960        cx.notify();
19961    }
19962
19963    pub fn clear_background_highlights<T: 'static>(
19964        &mut self,
19965        cx: &mut Context<Self>,
19966    ) -> Option<BackgroundHighlight> {
19967        let text_highlights = self
19968            .background_highlights
19969            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19970        if !text_highlights.1.is_empty() {
19971            self.scrollbar_marker_state.dirty = true;
19972            cx.notify();
19973        }
19974        Some(text_highlights)
19975    }
19976
19977    pub fn highlight_gutter<T: 'static>(
19978        &mut self,
19979        ranges: impl Into<Vec<Range<Anchor>>>,
19980        color_fetcher: fn(&App) -> Hsla,
19981        cx: &mut Context<Self>,
19982    ) {
19983        self.gutter_highlights
19984            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19985        cx.notify();
19986    }
19987
19988    pub fn clear_gutter_highlights<T: 'static>(
19989        &mut self,
19990        cx: &mut Context<Self>,
19991    ) -> Option<GutterHighlight> {
19992        cx.notify();
19993        self.gutter_highlights.remove(&TypeId::of::<T>())
19994    }
19995
19996    pub fn insert_gutter_highlight<T: 'static>(
19997        &mut self,
19998        range: Range<Anchor>,
19999        color_fetcher: fn(&App) -> Hsla,
20000        cx: &mut Context<Self>,
20001    ) {
20002        let snapshot = self.buffer().read(cx).snapshot(cx);
20003        let mut highlights = self
20004            .gutter_highlights
20005            .remove(&TypeId::of::<T>())
20006            .map(|(_, highlights)| highlights)
20007            .unwrap_or_default();
20008        let ix = highlights.binary_search_by(|highlight| {
20009            Ordering::Equal
20010                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20011                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20012        });
20013        if let Err(ix) = ix {
20014            highlights.insert(ix, range);
20015        }
20016        self.gutter_highlights
20017            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20018    }
20019
20020    pub fn remove_gutter_highlights<T: 'static>(
20021        &mut self,
20022        ranges_to_remove: Vec<Range<Anchor>>,
20023        cx: &mut Context<Self>,
20024    ) {
20025        let snapshot = self.buffer().read(cx).snapshot(cx);
20026        let Some((color_fetcher, mut gutter_highlights)) =
20027            self.gutter_highlights.remove(&TypeId::of::<T>())
20028        else {
20029            return;
20030        };
20031        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20032        gutter_highlights.retain(|highlight| {
20033            while let Some(range_to_remove) = ranges_to_remove.peek() {
20034                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20035                    Ordering::Less | Ordering::Equal => {
20036                        ranges_to_remove.next();
20037                    }
20038                    Ordering::Greater => {
20039                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20040                            Ordering::Less | Ordering::Equal => {
20041                                return false;
20042                            }
20043                            Ordering::Greater => break,
20044                        }
20045                    }
20046                }
20047            }
20048
20049            true
20050        });
20051        self.gutter_highlights
20052            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20053    }
20054
20055    #[cfg(feature = "test-support")]
20056    pub fn all_text_highlights(
20057        &self,
20058        window: &mut Window,
20059        cx: &mut Context<Self>,
20060    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20061        let snapshot = self.snapshot(window, cx);
20062        self.display_map.update(cx, |display_map, _| {
20063            display_map
20064                .all_text_highlights()
20065                .map(|highlight| {
20066                    let (style, ranges) = highlight.as_ref();
20067                    (
20068                        *style,
20069                        ranges
20070                            .iter()
20071                            .map(|range| range.clone().to_display_points(&snapshot))
20072                            .collect(),
20073                    )
20074                })
20075                .collect()
20076        })
20077    }
20078
20079    #[cfg(feature = "test-support")]
20080    pub fn all_text_background_highlights(
20081        &self,
20082        window: &mut Window,
20083        cx: &mut Context<Self>,
20084    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20085        let snapshot = self.snapshot(window, cx);
20086        let buffer = &snapshot.buffer_snapshot;
20087        let start = buffer.anchor_before(0);
20088        let end = buffer.anchor_after(buffer.len());
20089        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20090    }
20091
20092    #[cfg(any(test, feature = "test-support"))]
20093    pub fn sorted_background_highlights_in_range(
20094        &self,
20095        search_range: Range<Anchor>,
20096        display_snapshot: &DisplaySnapshot,
20097        theme: &Theme,
20098    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20099        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20100        res.sort_by(|a, b| {
20101            a.0.start
20102                .cmp(&b.0.start)
20103                .then_with(|| a.0.end.cmp(&b.0.end))
20104                .then_with(|| a.1.cmp(&b.1))
20105        });
20106        res
20107    }
20108
20109    #[cfg(feature = "test-support")]
20110    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20111        let snapshot = self.buffer().read(cx).snapshot(cx);
20112
20113        let highlights = self
20114            .background_highlights
20115            .get(&HighlightKey::Type(TypeId::of::<
20116                items::BufferSearchHighlights,
20117            >()));
20118
20119        if let Some((_color, ranges)) = highlights {
20120            ranges
20121                .iter()
20122                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20123                .collect_vec()
20124        } else {
20125            vec![]
20126        }
20127    }
20128
20129    fn document_highlights_for_position<'a>(
20130        &'a self,
20131        position: Anchor,
20132        buffer: &'a MultiBufferSnapshot,
20133    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20134        let read_highlights = self
20135            .background_highlights
20136            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20137            .map(|h| &h.1);
20138        let write_highlights = self
20139            .background_highlights
20140            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20141            .map(|h| &h.1);
20142        let left_position = position.bias_left(buffer);
20143        let right_position = position.bias_right(buffer);
20144        read_highlights
20145            .into_iter()
20146            .chain(write_highlights)
20147            .flat_map(move |ranges| {
20148                let start_ix = match ranges.binary_search_by(|probe| {
20149                    let cmp = probe.end.cmp(&left_position, buffer);
20150                    if cmp.is_ge() {
20151                        Ordering::Greater
20152                    } else {
20153                        Ordering::Less
20154                    }
20155                }) {
20156                    Ok(i) | Err(i) => i,
20157                };
20158
20159                ranges[start_ix..]
20160                    .iter()
20161                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20162            })
20163    }
20164
20165    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20166        self.background_highlights
20167            .get(&HighlightKey::Type(TypeId::of::<T>()))
20168            .is_some_and(|(_, highlights)| !highlights.is_empty())
20169    }
20170
20171    /// Returns all background highlights for a given range.
20172    ///
20173    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20174    pub fn background_highlights_in_range(
20175        &self,
20176        search_range: Range<Anchor>,
20177        display_snapshot: &DisplaySnapshot,
20178        theme: &Theme,
20179    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20180        let mut results = Vec::new();
20181        for (color_fetcher, ranges) in self.background_highlights.values() {
20182            let color = color_fetcher(theme);
20183            let start_ix = match ranges.binary_search_by(|probe| {
20184                let cmp = probe
20185                    .end
20186                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20187                if cmp.is_gt() {
20188                    Ordering::Greater
20189                } else {
20190                    Ordering::Less
20191                }
20192            }) {
20193                Ok(i) | Err(i) => i,
20194            };
20195            for range in &ranges[start_ix..] {
20196                if range
20197                    .start
20198                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20199                    .is_ge()
20200                {
20201                    break;
20202                }
20203
20204                let start = range.start.to_display_point(display_snapshot);
20205                let end = range.end.to_display_point(display_snapshot);
20206                results.push((start..end, color))
20207            }
20208        }
20209        results
20210    }
20211
20212    pub fn gutter_highlights_in_range(
20213        &self,
20214        search_range: Range<Anchor>,
20215        display_snapshot: &DisplaySnapshot,
20216        cx: &App,
20217    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20218        let mut results = Vec::new();
20219        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20220            let color = color_fetcher(cx);
20221            let start_ix = match ranges.binary_search_by(|probe| {
20222                let cmp = probe
20223                    .end
20224                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20225                if cmp.is_gt() {
20226                    Ordering::Greater
20227                } else {
20228                    Ordering::Less
20229                }
20230            }) {
20231                Ok(i) | Err(i) => i,
20232            };
20233            for range in &ranges[start_ix..] {
20234                if range
20235                    .start
20236                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20237                    .is_ge()
20238                {
20239                    break;
20240                }
20241
20242                let start = range.start.to_display_point(display_snapshot);
20243                let end = range.end.to_display_point(display_snapshot);
20244                results.push((start..end, color))
20245            }
20246        }
20247        results
20248    }
20249
20250    /// Get the text ranges corresponding to the redaction query
20251    pub fn redacted_ranges(
20252        &self,
20253        search_range: Range<Anchor>,
20254        display_snapshot: &DisplaySnapshot,
20255        cx: &App,
20256    ) -> Vec<Range<DisplayPoint>> {
20257        display_snapshot
20258            .buffer_snapshot
20259            .redacted_ranges(search_range, |file| {
20260                if let Some(file) = file {
20261                    file.is_private()
20262                        && EditorSettings::get(
20263                            Some(SettingsLocation {
20264                                worktree_id: file.worktree_id(cx),
20265                                path: file.path().as_ref(),
20266                            }),
20267                            cx,
20268                        )
20269                        .redact_private_values
20270                } else {
20271                    false
20272                }
20273            })
20274            .map(|range| {
20275                range.start.to_display_point(display_snapshot)
20276                    ..range.end.to_display_point(display_snapshot)
20277            })
20278            .collect()
20279    }
20280
20281    pub fn highlight_text_key<T: 'static>(
20282        &mut self,
20283        key: usize,
20284        ranges: Vec<Range<Anchor>>,
20285        style: HighlightStyle,
20286        cx: &mut Context<Self>,
20287    ) {
20288        self.display_map.update(cx, |map, _| {
20289            map.highlight_text(
20290                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20291                ranges,
20292                style,
20293            );
20294        });
20295        cx.notify();
20296    }
20297
20298    pub fn highlight_text<T: 'static>(
20299        &mut self,
20300        ranges: Vec<Range<Anchor>>,
20301        style: HighlightStyle,
20302        cx: &mut Context<Self>,
20303    ) {
20304        self.display_map.update(cx, |map, _| {
20305            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20306        });
20307        cx.notify();
20308    }
20309
20310    pub(crate) fn highlight_inlays<T: 'static>(
20311        &mut self,
20312        highlights: Vec<InlayHighlight>,
20313        style: HighlightStyle,
20314        cx: &mut Context<Self>,
20315    ) {
20316        self.display_map.update(cx, |map, _| {
20317            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20318        });
20319        cx.notify();
20320    }
20321
20322    pub fn text_highlights<'a, T: 'static>(
20323        &'a self,
20324        cx: &'a App,
20325    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20326        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20327    }
20328
20329    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20330        let cleared = self
20331            .display_map
20332            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20333        if cleared {
20334            cx.notify();
20335        }
20336    }
20337
20338    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20339        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20340            && self.focus_handle.is_focused(window)
20341    }
20342
20343    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20344        self.show_cursor_when_unfocused = is_enabled;
20345        cx.notify();
20346    }
20347
20348    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20349        cx.notify();
20350    }
20351
20352    fn on_debug_session_event(
20353        &mut self,
20354        _session: Entity<Session>,
20355        event: &SessionEvent,
20356        cx: &mut Context<Self>,
20357    ) {
20358        if let SessionEvent::InvalidateInlineValue = event {
20359            self.refresh_inline_values(cx);
20360        }
20361    }
20362
20363    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20364        let Some(project) = self.project.clone() else {
20365            return;
20366        };
20367
20368        if !self.inline_value_cache.enabled {
20369            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20370            self.splice_inlays(&inlays, Vec::new(), cx);
20371            return;
20372        }
20373
20374        let current_execution_position = self
20375            .highlighted_rows
20376            .get(&TypeId::of::<ActiveDebugLine>())
20377            .and_then(|lines| lines.last().map(|line| line.range.end));
20378
20379        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20380            let inline_values = editor
20381                .update(cx, |editor, cx| {
20382                    let Some(current_execution_position) = current_execution_position else {
20383                        return Some(Task::ready(Ok(Vec::new())));
20384                    };
20385
20386                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20387                        let snapshot = buffer.snapshot(cx);
20388
20389                        let excerpt = snapshot.excerpt_containing(
20390                            current_execution_position..current_execution_position,
20391                        )?;
20392
20393                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20394                    })?;
20395
20396                    let range =
20397                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20398
20399                    project.inline_values(buffer, range, cx)
20400                })
20401                .ok()
20402                .flatten()?
20403                .await
20404                .context("refreshing debugger inlays")
20405                .log_err()?;
20406
20407            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20408
20409            for (buffer_id, inline_value) in inline_values
20410                .into_iter()
20411                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20412            {
20413                buffer_inline_values
20414                    .entry(buffer_id)
20415                    .or_default()
20416                    .push(inline_value);
20417            }
20418
20419            editor
20420                .update(cx, |editor, cx| {
20421                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20422                    let mut new_inlays = Vec::default();
20423
20424                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20425                        let buffer_id = buffer_snapshot.remote_id();
20426                        buffer_inline_values
20427                            .get(&buffer_id)
20428                            .into_iter()
20429                            .flatten()
20430                            .for_each(|hint| {
20431                                let inlay = Inlay::debugger(
20432                                    post_inc(&mut editor.next_inlay_id),
20433                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20434                                    hint.text(),
20435                                );
20436                                if !inlay.text.chars().contains(&'\n') {
20437                                    new_inlays.push(inlay);
20438                                }
20439                            });
20440                    }
20441
20442                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20443                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20444
20445                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20446                })
20447                .ok()?;
20448            Some(())
20449        });
20450    }
20451
20452    fn on_buffer_event(
20453        &mut self,
20454        multibuffer: &Entity<MultiBuffer>,
20455        event: &multi_buffer::Event,
20456        window: &mut Window,
20457        cx: &mut Context<Self>,
20458    ) {
20459        match event {
20460            multi_buffer::Event::Edited {
20461                singleton_buffer_edited,
20462                edited_buffer,
20463            } => {
20464                self.scrollbar_marker_state.dirty = true;
20465                self.active_indent_guides_state.dirty = true;
20466                self.refresh_active_diagnostics(cx);
20467                self.refresh_code_actions(window, cx);
20468                self.refresh_selected_text_highlights(true, window, cx);
20469                self.refresh_single_line_folds(window, cx);
20470                refresh_matching_bracket_highlights(self, window, cx);
20471                if self.has_active_edit_prediction() {
20472                    self.update_visible_edit_prediction(window, cx);
20473                }
20474                if let Some(project) = self.project.as_ref()
20475                    && let Some(edited_buffer) = edited_buffer
20476                {
20477                    project.update(cx, |project, cx| {
20478                        self.registered_buffers
20479                            .entry(edited_buffer.read(cx).remote_id())
20480                            .or_insert_with(|| {
20481                                project.register_buffer_with_language_servers(edited_buffer, cx)
20482                            });
20483                    });
20484                }
20485                cx.emit(EditorEvent::BufferEdited);
20486                cx.emit(SearchEvent::MatchesInvalidated);
20487
20488                if let Some(buffer) = edited_buffer {
20489                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20490                }
20491
20492                if *singleton_buffer_edited {
20493                    if let Some(buffer) = edited_buffer
20494                        && buffer.read(cx).file().is_none()
20495                    {
20496                        cx.emit(EditorEvent::TitleChanged);
20497                    }
20498                    if let Some(project) = &self.project {
20499                        #[allow(clippy::mutable_key_type)]
20500                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20501                            multibuffer
20502                                .all_buffers()
20503                                .into_iter()
20504                                .filter_map(|buffer| {
20505                                    buffer.update(cx, |buffer, cx| {
20506                                        let language = buffer.language()?;
20507                                        let should_discard = project.update(cx, |project, cx| {
20508                                            project.is_local()
20509                                                && !project.has_language_servers_for(buffer, cx)
20510                                        });
20511                                        should_discard.not().then_some(language.clone())
20512                                    })
20513                                })
20514                                .collect::<HashSet<_>>()
20515                        });
20516                        if !languages_affected.is_empty() {
20517                            self.refresh_inlay_hints(
20518                                InlayHintRefreshReason::BufferEdited(languages_affected),
20519                                cx,
20520                            );
20521                        }
20522                    }
20523                }
20524
20525                let Some(project) = &self.project else { return };
20526                let (telemetry, is_via_ssh) = {
20527                    let project = project.read(cx);
20528                    let telemetry = project.client().telemetry().clone();
20529                    let is_via_ssh = project.is_via_remote_server();
20530                    (telemetry, is_via_ssh)
20531                };
20532                refresh_linked_ranges(self, window, cx);
20533                telemetry.log_edit_event("editor", is_via_ssh);
20534            }
20535            multi_buffer::Event::ExcerptsAdded {
20536                buffer,
20537                predecessor,
20538                excerpts,
20539            } => {
20540                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20541                let buffer_id = buffer.read(cx).remote_id();
20542                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20543                    && let Some(project) = &self.project
20544                {
20545                    update_uncommitted_diff_for_buffer(
20546                        cx.entity(),
20547                        project,
20548                        [buffer.clone()],
20549                        self.buffer.clone(),
20550                        cx,
20551                    )
20552                    .detach();
20553                }
20554                self.update_lsp_data(false, Some(buffer_id), window, cx);
20555                cx.emit(EditorEvent::ExcerptsAdded {
20556                    buffer: buffer.clone(),
20557                    predecessor: *predecessor,
20558                    excerpts: excerpts.clone(),
20559                });
20560                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20561            }
20562            multi_buffer::Event::ExcerptsRemoved {
20563                ids,
20564                removed_buffer_ids,
20565            } => {
20566                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20567                let buffer = self.buffer.read(cx);
20568                self.registered_buffers
20569                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20570                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20571                cx.emit(EditorEvent::ExcerptsRemoved {
20572                    ids: ids.clone(),
20573                    removed_buffer_ids: removed_buffer_ids.clone(),
20574                });
20575            }
20576            multi_buffer::Event::ExcerptsEdited {
20577                excerpt_ids,
20578                buffer_ids,
20579            } => {
20580                self.display_map.update(cx, |map, cx| {
20581                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20582                });
20583                cx.emit(EditorEvent::ExcerptsEdited {
20584                    ids: excerpt_ids.clone(),
20585                });
20586            }
20587            multi_buffer::Event::ExcerptsExpanded { ids } => {
20588                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20589                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20590            }
20591            multi_buffer::Event::Reparsed(buffer_id) => {
20592                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20593                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20594
20595                cx.emit(EditorEvent::Reparsed(*buffer_id));
20596            }
20597            multi_buffer::Event::DiffHunksToggled => {
20598                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20599            }
20600            multi_buffer::Event::LanguageChanged(buffer_id) => {
20601                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20602                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20603                cx.emit(EditorEvent::Reparsed(*buffer_id));
20604                cx.notify();
20605            }
20606            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20607            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20608            multi_buffer::Event::FileHandleChanged
20609            | multi_buffer::Event::Reloaded
20610            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20611            multi_buffer::Event::DiagnosticsUpdated => {
20612                self.update_diagnostics_state(window, cx);
20613            }
20614            _ => {}
20615        };
20616    }
20617
20618    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20619        if !self.diagnostics_enabled() {
20620            return;
20621        }
20622        self.refresh_active_diagnostics(cx);
20623        self.refresh_inline_diagnostics(true, window, cx);
20624        self.scrollbar_marker_state.dirty = true;
20625        cx.notify();
20626    }
20627
20628    pub fn start_temporary_diff_override(&mut self) {
20629        self.load_diff_task.take();
20630        self.temporary_diff_override = true;
20631    }
20632
20633    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20634        self.temporary_diff_override = false;
20635        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20636        self.buffer.update(cx, |buffer, cx| {
20637            buffer.set_all_diff_hunks_collapsed(cx);
20638        });
20639
20640        if let Some(project) = self.project.clone() {
20641            self.load_diff_task = Some(
20642                update_uncommitted_diff_for_buffer(
20643                    cx.entity(),
20644                    &project,
20645                    self.buffer.read(cx).all_buffers(),
20646                    self.buffer.clone(),
20647                    cx,
20648                )
20649                .shared(),
20650            );
20651        }
20652    }
20653
20654    fn on_display_map_changed(
20655        &mut self,
20656        _: Entity<DisplayMap>,
20657        _: &mut Window,
20658        cx: &mut Context<Self>,
20659    ) {
20660        cx.notify();
20661    }
20662
20663    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20664        if self.diagnostics_enabled() {
20665            let new_severity = EditorSettings::get_global(cx)
20666                .diagnostics_max_severity
20667                .unwrap_or(DiagnosticSeverity::Hint);
20668            self.set_max_diagnostics_severity(new_severity, cx);
20669        }
20670        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20671        self.update_edit_prediction_settings(cx);
20672        self.refresh_edit_prediction(true, false, window, cx);
20673        self.refresh_inline_values(cx);
20674        self.refresh_inlay_hints(
20675            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20676                self.selections.newest_anchor().head(),
20677                &self.buffer.read(cx).snapshot(cx),
20678                cx,
20679            )),
20680            cx,
20681        );
20682
20683        let old_cursor_shape = self.cursor_shape;
20684        let old_show_breadcrumbs = self.show_breadcrumbs;
20685
20686        {
20687            let editor_settings = EditorSettings::get_global(cx);
20688            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20689            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20690            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20691            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20692        }
20693
20694        if old_cursor_shape != self.cursor_shape {
20695            cx.emit(EditorEvent::CursorShapeChanged);
20696        }
20697
20698        if old_show_breadcrumbs != self.show_breadcrumbs {
20699            cx.emit(EditorEvent::BreadcrumbsChanged);
20700        }
20701
20702        let project_settings = ProjectSettings::get_global(cx);
20703        self.serialize_dirty_buffers =
20704            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20705
20706        if self.mode.is_full() {
20707            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20708            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20709            if self.show_inline_diagnostics != show_inline_diagnostics {
20710                self.show_inline_diagnostics = show_inline_diagnostics;
20711                self.refresh_inline_diagnostics(false, window, cx);
20712            }
20713
20714            if self.git_blame_inline_enabled != inline_blame_enabled {
20715                self.toggle_git_blame_inline_internal(false, window, cx);
20716            }
20717
20718            let minimap_settings = EditorSettings::get_global(cx).minimap;
20719            if self.minimap_visibility != MinimapVisibility::Disabled {
20720                if self.minimap_visibility.settings_visibility()
20721                    != minimap_settings.minimap_enabled()
20722                {
20723                    self.set_minimap_visibility(
20724                        MinimapVisibility::for_mode(self.mode(), cx),
20725                        window,
20726                        cx,
20727                    );
20728                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20729                    minimap_entity.update(cx, |minimap_editor, cx| {
20730                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20731                    })
20732                }
20733            }
20734        }
20735
20736        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20737            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20738        }) {
20739            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20740                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20741            }
20742            self.refresh_colors(false, None, window, cx);
20743        }
20744
20745        cx.notify();
20746    }
20747
20748    pub fn set_searchable(&mut self, searchable: bool) {
20749        self.searchable = searchable;
20750    }
20751
20752    pub fn searchable(&self) -> bool {
20753        self.searchable
20754    }
20755
20756    fn open_proposed_changes_editor(
20757        &mut self,
20758        _: &OpenProposedChangesEditor,
20759        window: &mut Window,
20760        cx: &mut Context<Self>,
20761    ) {
20762        let Some(workspace) = self.workspace() else {
20763            cx.propagate();
20764            return;
20765        };
20766
20767        let selections = self.selections.all::<usize>(cx);
20768        let multi_buffer = self.buffer.read(cx);
20769        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20770        let mut new_selections_by_buffer = HashMap::default();
20771        for selection in selections {
20772            for (buffer, range, _) in
20773                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20774            {
20775                let mut range = range.to_point(buffer);
20776                range.start.column = 0;
20777                range.end.column = buffer.line_len(range.end.row);
20778                new_selections_by_buffer
20779                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20780                    .or_insert(Vec::new())
20781                    .push(range)
20782            }
20783        }
20784
20785        let proposed_changes_buffers = new_selections_by_buffer
20786            .into_iter()
20787            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20788            .collect::<Vec<_>>();
20789        let proposed_changes_editor = cx.new(|cx| {
20790            ProposedChangesEditor::new(
20791                "Proposed changes",
20792                proposed_changes_buffers,
20793                self.project.clone(),
20794                window,
20795                cx,
20796            )
20797        });
20798
20799        window.defer(cx, move |window, cx| {
20800            workspace.update(cx, |workspace, cx| {
20801                workspace.active_pane().update(cx, |pane, cx| {
20802                    pane.add_item(
20803                        Box::new(proposed_changes_editor),
20804                        true,
20805                        true,
20806                        None,
20807                        window,
20808                        cx,
20809                    );
20810                });
20811            });
20812        });
20813    }
20814
20815    pub fn open_excerpts_in_split(
20816        &mut self,
20817        _: &OpenExcerptsSplit,
20818        window: &mut Window,
20819        cx: &mut Context<Self>,
20820    ) {
20821        self.open_excerpts_common(None, true, window, cx)
20822    }
20823
20824    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20825        self.open_excerpts_common(None, false, window, cx)
20826    }
20827
20828    fn open_excerpts_common(
20829        &mut self,
20830        jump_data: Option<JumpData>,
20831        split: bool,
20832        window: &mut Window,
20833        cx: &mut Context<Self>,
20834    ) {
20835        let Some(workspace) = self.workspace() else {
20836            cx.propagate();
20837            return;
20838        };
20839
20840        if self.buffer.read(cx).is_singleton() {
20841            cx.propagate();
20842            return;
20843        }
20844
20845        let mut new_selections_by_buffer = HashMap::default();
20846        match &jump_data {
20847            Some(JumpData::MultiBufferPoint {
20848                excerpt_id,
20849                position,
20850                anchor,
20851                line_offset_from_top,
20852            }) => {
20853                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20854                if let Some(buffer) = multi_buffer_snapshot
20855                    .buffer_id_for_excerpt(*excerpt_id)
20856                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20857                {
20858                    let buffer_snapshot = buffer.read(cx).snapshot();
20859                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20860                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20861                    } else {
20862                        buffer_snapshot.clip_point(*position, Bias::Left)
20863                    };
20864                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20865                    new_selections_by_buffer.insert(
20866                        buffer,
20867                        (
20868                            vec![jump_to_offset..jump_to_offset],
20869                            Some(*line_offset_from_top),
20870                        ),
20871                    );
20872                }
20873            }
20874            Some(JumpData::MultiBufferRow {
20875                row,
20876                line_offset_from_top,
20877            }) => {
20878                let point = MultiBufferPoint::new(row.0, 0);
20879                if let Some((buffer, buffer_point, _)) =
20880                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20881                {
20882                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20883                    new_selections_by_buffer
20884                        .entry(buffer)
20885                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20886                        .0
20887                        .push(buffer_offset..buffer_offset)
20888                }
20889            }
20890            None => {
20891                let selections = self.selections.all::<usize>(cx);
20892                let multi_buffer = self.buffer.read(cx);
20893                for selection in selections {
20894                    for (snapshot, range, _, anchor) in multi_buffer
20895                        .snapshot(cx)
20896                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20897                    {
20898                        if let Some(anchor) = anchor {
20899                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20900                            else {
20901                                continue;
20902                            };
20903                            let offset = text::ToOffset::to_offset(
20904                                &anchor.text_anchor,
20905                                &buffer_handle.read(cx).snapshot(),
20906                            );
20907                            let range = offset..offset;
20908                            new_selections_by_buffer
20909                                .entry(buffer_handle)
20910                                .or_insert((Vec::new(), None))
20911                                .0
20912                                .push(range)
20913                        } else {
20914                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20915                            else {
20916                                continue;
20917                            };
20918                            new_selections_by_buffer
20919                                .entry(buffer_handle)
20920                                .or_insert((Vec::new(), None))
20921                                .0
20922                                .push(range)
20923                        }
20924                    }
20925                }
20926            }
20927        }
20928
20929        new_selections_by_buffer
20930            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20931
20932        if new_selections_by_buffer.is_empty() {
20933            return;
20934        }
20935
20936        // We defer the pane interaction because we ourselves are a workspace item
20937        // and activating a new item causes the pane to call a method on us reentrantly,
20938        // which panics if we're on the stack.
20939        window.defer(cx, move |window, cx| {
20940            workspace.update(cx, |workspace, cx| {
20941                let pane = if split {
20942                    workspace.adjacent_pane(window, cx)
20943                } else {
20944                    workspace.active_pane().clone()
20945                };
20946
20947                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20948                    let editor = buffer
20949                        .read(cx)
20950                        .file()
20951                        .is_none()
20952                        .then(|| {
20953                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20954                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20955                            // Instead, we try to activate the existing editor in the pane first.
20956                            let (editor, pane_item_index) =
20957                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20958                                    let editor = item.downcast::<Editor>()?;
20959                                    let singleton_buffer =
20960                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20961                                    if singleton_buffer == buffer {
20962                                        Some((editor, i))
20963                                    } else {
20964                                        None
20965                                    }
20966                                })?;
20967                            pane.update(cx, |pane, cx| {
20968                                pane.activate_item(pane_item_index, true, true, window, cx)
20969                            });
20970                            Some(editor)
20971                        })
20972                        .flatten()
20973                        .unwrap_or_else(|| {
20974                            workspace.open_project_item::<Self>(
20975                                pane.clone(),
20976                                buffer,
20977                                true,
20978                                true,
20979                                window,
20980                                cx,
20981                            )
20982                        });
20983
20984                    editor.update(cx, |editor, cx| {
20985                        let autoscroll = match scroll_offset {
20986                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20987                            None => Autoscroll::newest(),
20988                        };
20989                        let nav_history = editor.nav_history.take();
20990                        editor.change_selections(
20991                            SelectionEffects::scroll(autoscroll),
20992                            window,
20993                            cx,
20994                            |s| {
20995                                s.select_ranges(ranges);
20996                            },
20997                        );
20998                        editor.nav_history = nav_history;
20999                    });
21000                }
21001            })
21002        });
21003    }
21004
21005    // For now, don't allow opening excerpts in buffers that aren't backed by
21006    // regular project files.
21007    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21008        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21009    }
21010
21011    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21012        let snapshot = self.buffer.read(cx).read(cx);
21013        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21014        Some(
21015            ranges
21016                .iter()
21017                .map(move |range| {
21018                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21019                })
21020                .collect(),
21021        )
21022    }
21023
21024    fn selection_replacement_ranges(
21025        &self,
21026        range: Range<OffsetUtf16>,
21027        cx: &mut App,
21028    ) -> Vec<Range<OffsetUtf16>> {
21029        let selections = self.selections.all::<OffsetUtf16>(cx);
21030        let newest_selection = selections
21031            .iter()
21032            .max_by_key(|selection| selection.id)
21033            .unwrap();
21034        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21035        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21036        let snapshot = self.buffer.read(cx).read(cx);
21037        selections
21038            .into_iter()
21039            .map(|mut selection| {
21040                selection.start.0 =
21041                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21042                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21043                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21044                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21045            })
21046            .collect()
21047    }
21048
21049    fn report_editor_event(
21050        &self,
21051        reported_event: ReportEditorEvent,
21052        file_extension: Option<String>,
21053        cx: &App,
21054    ) {
21055        if cfg!(any(test, feature = "test-support")) {
21056            return;
21057        }
21058
21059        let Some(project) = &self.project else { return };
21060
21061        // If None, we are in a file without an extension
21062        let file = self
21063            .buffer
21064            .read(cx)
21065            .as_singleton()
21066            .and_then(|b| b.read(cx).file());
21067        let file_extension = file_extension.or(file
21068            .as_ref()
21069            .and_then(|file| Path::new(file.file_name(cx)).extension())
21070            .and_then(|e| e.to_str())
21071            .map(|a| a.to_string()));
21072
21073        let vim_mode = vim_enabled(cx);
21074
21075        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21076        let copilot_enabled = edit_predictions_provider
21077            == language::language_settings::EditPredictionProvider::Copilot;
21078        let copilot_enabled_for_language = self
21079            .buffer
21080            .read(cx)
21081            .language_settings(cx)
21082            .show_edit_predictions;
21083
21084        let project = project.read(cx);
21085        let event_type = reported_event.event_type();
21086
21087        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21088            telemetry::event!(
21089                event_type,
21090                type = if auto_saved {"autosave"} else {"manual"},
21091                file_extension,
21092                vim_mode,
21093                copilot_enabled,
21094                copilot_enabled_for_language,
21095                edit_predictions_provider,
21096                is_via_ssh = project.is_via_remote_server(),
21097            );
21098        } else {
21099            telemetry::event!(
21100                event_type,
21101                file_extension,
21102                vim_mode,
21103                copilot_enabled,
21104                copilot_enabled_for_language,
21105                edit_predictions_provider,
21106                is_via_ssh = project.is_via_remote_server(),
21107            );
21108        };
21109    }
21110
21111    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21112    /// with each line being an array of {text, highlight} objects.
21113    fn copy_highlight_json(
21114        &mut self,
21115        _: &CopyHighlightJson,
21116        window: &mut Window,
21117        cx: &mut Context<Self>,
21118    ) {
21119        #[derive(Serialize)]
21120        struct Chunk<'a> {
21121            text: String,
21122            highlight: Option<&'a str>,
21123        }
21124
21125        let snapshot = self.buffer.read(cx).snapshot(cx);
21126        let range = self
21127            .selected_text_range(false, window, cx)
21128            .and_then(|selection| {
21129                if selection.range.is_empty() {
21130                    None
21131                } else {
21132                    Some(selection.range)
21133                }
21134            })
21135            .unwrap_or_else(|| 0..snapshot.len());
21136
21137        let chunks = snapshot.chunks(range, true);
21138        let mut lines = Vec::new();
21139        let mut line: VecDeque<Chunk> = VecDeque::new();
21140
21141        let Some(style) = self.style.as_ref() else {
21142            return;
21143        };
21144
21145        for chunk in chunks {
21146            let highlight = chunk
21147                .syntax_highlight_id
21148                .and_then(|id| id.name(&style.syntax));
21149            let mut chunk_lines = chunk.text.split('\n').peekable();
21150            while let Some(text) = chunk_lines.next() {
21151                let mut merged_with_last_token = false;
21152                if let Some(last_token) = line.back_mut()
21153                    && last_token.highlight == highlight
21154                {
21155                    last_token.text.push_str(text);
21156                    merged_with_last_token = true;
21157                }
21158
21159                if !merged_with_last_token {
21160                    line.push_back(Chunk {
21161                        text: text.into(),
21162                        highlight,
21163                    });
21164                }
21165
21166                if chunk_lines.peek().is_some() {
21167                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21168                        line.pop_front();
21169                    }
21170                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21171                        line.pop_back();
21172                    }
21173
21174                    lines.push(mem::take(&mut line));
21175                }
21176            }
21177        }
21178
21179        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21180            return;
21181        };
21182        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21183    }
21184
21185    pub fn open_context_menu(
21186        &mut self,
21187        _: &OpenContextMenu,
21188        window: &mut Window,
21189        cx: &mut Context<Self>,
21190    ) {
21191        self.request_autoscroll(Autoscroll::newest(), cx);
21192        let position = self.selections.newest_display(cx).start;
21193        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21194    }
21195
21196    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21197        &self.inlay_hint_cache
21198    }
21199
21200    pub fn replay_insert_event(
21201        &mut self,
21202        text: &str,
21203        relative_utf16_range: Option<Range<isize>>,
21204        window: &mut Window,
21205        cx: &mut Context<Self>,
21206    ) {
21207        if !self.input_enabled {
21208            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21209            return;
21210        }
21211        if let Some(relative_utf16_range) = relative_utf16_range {
21212            let selections = self.selections.all::<OffsetUtf16>(cx);
21213            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21214                let new_ranges = selections.into_iter().map(|range| {
21215                    let start = OffsetUtf16(
21216                        range
21217                            .head()
21218                            .0
21219                            .saturating_add_signed(relative_utf16_range.start),
21220                    );
21221                    let end = OffsetUtf16(
21222                        range
21223                            .head()
21224                            .0
21225                            .saturating_add_signed(relative_utf16_range.end),
21226                    );
21227                    start..end
21228                });
21229                s.select_ranges(new_ranges);
21230            });
21231        }
21232
21233        self.handle_input(text, window, cx);
21234    }
21235
21236    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21237        let Some(provider) = self.semantics_provider.as_ref() else {
21238            return false;
21239        };
21240
21241        let mut supports = false;
21242        self.buffer().update(cx, |this, cx| {
21243            this.for_each_buffer(|buffer| {
21244                supports |= provider.supports_inlay_hints(buffer, cx);
21245            });
21246        });
21247
21248        supports
21249    }
21250
21251    pub fn is_focused(&self, window: &Window) -> bool {
21252        self.focus_handle.is_focused(window)
21253    }
21254
21255    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21256        cx.emit(EditorEvent::Focused);
21257
21258        if let Some(descendant) = self
21259            .last_focused_descendant
21260            .take()
21261            .and_then(|descendant| descendant.upgrade())
21262        {
21263            window.focus(&descendant);
21264        } else {
21265            if let Some(blame) = self.blame.as_ref() {
21266                blame.update(cx, GitBlame::focus)
21267            }
21268
21269            self.blink_manager.update(cx, BlinkManager::enable);
21270            self.show_cursor_names(window, cx);
21271            self.buffer.update(cx, |buffer, cx| {
21272                buffer.finalize_last_transaction(cx);
21273                if self.leader_id.is_none() {
21274                    buffer.set_active_selections(
21275                        &self.selections.disjoint_anchors(),
21276                        self.selections.line_mode,
21277                        self.cursor_shape,
21278                        cx,
21279                    );
21280                }
21281            });
21282        }
21283    }
21284
21285    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21286        cx.emit(EditorEvent::FocusedIn)
21287    }
21288
21289    fn handle_focus_out(
21290        &mut self,
21291        event: FocusOutEvent,
21292        _window: &mut Window,
21293        cx: &mut Context<Self>,
21294    ) {
21295        if event.blurred != self.focus_handle {
21296            self.last_focused_descendant = Some(event.blurred);
21297        }
21298        self.selection_drag_state = SelectionDragState::None;
21299        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21300    }
21301
21302    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21303        self.blink_manager.update(cx, BlinkManager::disable);
21304        self.buffer
21305            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21306
21307        if let Some(blame) = self.blame.as_ref() {
21308            blame.update(cx, GitBlame::blur)
21309        }
21310        if !self.hover_state.focused(window, cx) {
21311            hide_hover(self, cx);
21312        }
21313        if !self
21314            .context_menu
21315            .borrow()
21316            .as_ref()
21317            .is_some_and(|context_menu| context_menu.focused(window, cx))
21318        {
21319            self.hide_context_menu(window, cx);
21320        }
21321        self.discard_edit_prediction(false, cx);
21322        cx.emit(EditorEvent::Blurred);
21323        cx.notify();
21324    }
21325
21326    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21327        let mut pending: String = window
21328            .pending_input_keystrokes()
21329            .into_iter()
21330            .flatten()
21331            .filter_map(|keystroke| {
21332                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21333                    keystroke.key_char.clone()
21334                } else {
21335                    None
21336                }
21337            })
21338            .collect();
21339
21340        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21341            pending = "".to_string();
21342        }
21343
21344        let existing_pending = self
21345            .text_highlights::<PendingInput>(cx)
21346            .map(|(_, ranges)| ranges.to_vec());
21347        if existing_pending.is_none() && pending.is_empty() {
21348            return;
21349        }
21350        let transaction =
21351            self.transact(window, cx, |this, window, cx| {
21352                let selections = this.selections.all::<usize>(cx);
21353                let edits = selections
21354                    .iter()
21355                    .map(|selection| (selection.end..selection.end, pending.clone()));
21356                this.edit(edits, cx);
21357                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21358                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21359                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21360                    }));
21361                });
21362                if let Some(existing_ranges) = existing_pending {
21363                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21364                    this.edit(edits, cx);
21365                }
21366            });
21367
21368        let snapshot = self.snapshot(window, cx);
21369        let ranges = self
21370            .selections
21371            .all::<usize>(cx)
21372            .into_iter()
21373            .map(|selection| {
21374                snapshot.buffer_snapshot.anchor_after(selection.end)
21375                    ..snapshot
21376                        .buffer_snapshot
21377                        .anchor_before(selection.end + pending.len())
21378            })
21379            .collect();
21380
21381        if pending.is_empty() {
21382            self.clear_highlights::<PendingInput>(cx);
21383        } else {
21384            self.highlight_text::<PendingInput>(
21385                ranges,
21386                HighlightStyle {
21387                    underline: Some(UnderlineStyle {
21388                        thickness: px(1.),
21389                        color: None,
21390                        wavy: false,
21391                    }),
21392                    ..Default::default()
21393                },
21394                cx,
21395            );
21396        }
21397
21398        self.ime_transaction = self.ime_transaction.or(transaction);
21399        if let Some(transaction) = self.ime_transaction {
21400            self.buffer.update(cx, |buffer, cx| {
21401                buffer.group_until_transaction(transaction, cx);
21402            });
21403        }
21404
21405        if self.text_highlights::<PendingInput>(cx).is_none() {
21406            self.ime_transaction.take();
21407        }
21408    }
21409
21410    pub fn register_action_renderer(
21411        &mut self,
21412        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21413    ) -> Subscription {
21414        let id = self.next_editor_action_id.post_inc();
21415        self.editor_actions
21416            .borrow_mut()
21417            .insert(id, Box::new(listener));
21418
21419        let editor_actions = self.editor_actions.clone();
21420        Subscription::new(move || {
21421            editor_actions.borrow_mut().remove(&id);
21422        })
21423    }
21424
21425    pub fn register_action<A: Action>(
21426        &mut self,
21427        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21428    ) -> Subscription {
21429        let id = self.next_editor_action_id.post_inc();
21430        let listener = Arc::new(listener);
21431        self.editor_actions.borrow_mut().insert(
21432            id,
21433            Box::new(move |_, window, _| {
21434                let listener = listener.clone();
21435                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21436                    let action = action.downcast_ref().unwrap();
21437                    if phase == DispatchPhase::Bubble {
21438                        listener(action, window, cx)
21439                    }
21440                })
21441            }),
21442        );
21443
21444        let editor_actions = self.editor_actions.clone();
21445        Subscription::new(move || {
21446            editor_actions.borrow_mut().remove(&id);
21447        })
21448    }
21449
21450    pub fn file_header_size(&self) -> u32 {
21451        FILE_HEADER_HEIGHT
21452    }
21453
21454    pub fn restore(
21455        &mut self,
21456        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21457        window: &mut Window,
21458        cx: &mut Context<Self>,
21459    ) {
21460        let workspace = self.workspace();
21461        let project = self.project();
21462        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21463            let mut tasks = Vec::new();
21464            for (buffer_id, changes) in revert_changes {
21465                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21466                    buffer.update(cx, |buffer, cx| {
21467                        buffer.edit(
21468                            changes
21469                                .into_iter()
21470                                .map(|(range, text)| (range, text.to_string())),
21471                            None,
21472                            cx,
21473                        );
21474                    });
21475
21476                    if let Some(project) =
21477                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21478                    {
21479                        project.update(cx, |project, cx| {
21480                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21481                        })
21482                    }
21483                }
21484            }
21485            tasks
21486        });
21487        cx.spawn_in(window, async move |_, cx| {
21488            for (buffer, task) in save_tasks {
21489                let result = task.await;
21490                if result.is_err() {
21491                    let Some(path) = buffer
21492                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21493                        .ok()
21494                    else {
21495                        continue;
21496                    };
21497                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21498                        let Some(task) = cx
21499                            .update_window_entity(workspace, |workspace, window, cx| {
21500                                workspace
21501                                    .open_path_preview(path, None, false, false, false, window, cx)
21502                            })
21503                            .ok()
21504                        else {
21505                            continue;
21506                        };
21507                        task.await.log_err();
21508                    }
21509                }
21510            }
21511        })
21512        .detach();
21513        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21514            selections.refresh()
21515        });
21516    }
21517
21518    pub fn to_pixel_point(
21519        &self,
21520        source: multi_buffer::Anchor,
21521        editor_snapshot: &EditorSnapshot,
21522        window: &mut Window,
21523    ) -> Option<gpui::Point<Pixels>> {
21524        let source_point = source.to_display_point(editor_snapshot);
21525        self.display_to_pixel_point(source_point, editor_snapshot, window)
21526    }
21527
21528    pub fn display_to_pixel_point(
21529        &self,
21530        source: DisplayPoint,
21531        editor_snapshot: &EditorSnapshot,
21532        window: &mut Window,
21533    ) -> Option<gpui::Point<Pixels>> {
21534        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21535        let text_layout_details = self.text_layout_details(window);
21536        let scroll_top = text_layout_details
21537            .scroll_anchor
21538            .scroll_position(editor_snapshot)
21539            .y;
21540
21541        if source.row().as_f32() < scroll_top.floor() {
21542            return None;
21543        }
21544        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21545        let source_y = line_height * (source.row().as_f32() - scroll_top);
21546        Some(gpui::Point::new(source_x, source_y))
21547    }
21548
21549    pub fn has_visible_completions_menu(&self) -> bool {
21550        !self.edit_prediction_preview_is_active()
21551            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21552                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21553            })
21554    }
21555
21556    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21557        if self.mode.is_minimap() {
21558            return;
21559        }
21560        self.addons
21561            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21562    }
21563
21564    pub fn unregister_addon<T: Addon>(&mut self) {
21565        self.addons.remove(&std::any::TypeId::of::<T>());
21566    }
21567
21568    pub fn addon<T: Addon>(&self) -> Option<&T> {
21569        let type_id = std::any::TypeId::of::<T>();
21570        self.addons
21571            .get(&type_id)
21572            .and_then(|item| item.to_any().downcast_ref::<T>())
21573    }
21574
21575    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21576        let type_id = std::any::TypeId::of::<T>();
21577        self.addons
21578            .get_mut(&type_id)
21579            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21580    }
21581
21582    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21583        let text_layout_details = self.text_layout_details(window);
21584        let style = &text_layout_details.editor_style;
21585        let font_id = window.text_system().resolve_font(&style.text.font());
21586        let font_size = style.text.font_size.to_pixels(window.rem_size());
21587        let line_height = style.text.line_height_in_pixels(window.rem_size());
21588        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21589        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21590
21591        CharacterDimensions {
21592            em_width,
21593            em_advance,
21594            line_height,
21595        }
21596    }
21597
21598    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21599        self.load_diff_task.clone()
21600    }
21601
21602    fn read_metadata_from_db(
21603        &mut self,
21604        item_id: u64,
21605        workspace_id: WorkspaceId,
21606        window: &mut Window,
21607        cx: &mut Context<Editor>,
21608    ) {
21609        if self.is_singleton(cx)
21610            && !self.mode.is_minimap()
21611            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21612        {
21613            let buffer_snapshot = OnceCell::new();
21614
21615            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21616                && !folds.is_empty()
21617            {
21618                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21619                self.fold_ranges(
21620                    folds
21621                        .into_iter()
21622                        .map(|(start, end)| {
21623                            snapshot.clip_offset(start, Bias::Left)
21624                                ..snapshot.clip_offset(end, Bias::Right)
21625                        })
21626                        .collect(),
21627                    false,
21628                    window,
21629                    cx,
21630                );
21631            }
21632
21633            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21634                && !selections.is_empty()
21635            {
21636                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21637                // skip adding the initial selection to selection history
21638                self.selection_history.mode = SelectionHistoryMode::Skipping;
21639                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21640                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21641                        snapshot.clip_offset(start, Bias::Left)
21642                            ..snapshot.clip_offset(end, Bias::Right)
21643                    }));
21644                });
21645                self.selection_history.mode = SelectionHistoryMode::Normal;
21646            };
21647        }
21648
21649        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21650    }
21651
21652    fn update_lsp_data(
21653        &mut self,
21654        ignore_cache: bool,
21655        for_buffer: Option<BufferId>,
21656        window: &mut Window,
21657        cx: &mut Context<'_, Self>,
21658    ) {
21659        self.pull_diagnostics(for_buffer, window, cx);
21660        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21661    }
21662}
21663
21664// todo(settings_refactor) this should not be!
21665fn vim_enabled(cx: &App) -> bool {
21666    cx.global::<SettingsStore>()
21667        .raw_user_settings()
21668        .and_then(|settings| settings.content.vim_mode)
21669        == Some(true)
21670}
21671
21672fn process_completion_for_edit(
21673    completion: &Completion,
21674    intent: CompletionIntent,
21675    buffer: &Entity<Buffer>,
21676    cursor_position: &text::Anchor,
21677    cx: &mut Context<Editor>,
21678) -> CompletionEdit {
21679    let buffer = buffer.read(cx);
21680    let buffer_snapshot = buffer.snapshot();
21681    let (snippet, new_text) = if completion.is_snippet() {
21682        // Workaround for typescript language server issues so that methods don't expand within
21683        // strings and functions with type expressions. The previous point is used because the query
21684        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21685        let mut snippet_source = completion.new_text.clone();
21686        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21687        previous_point.column = previous_point.column.saturating_sub(1);
21688        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21689            && scope.prefers_label_for_snippet_in_completion()
21690            && let Some(label) = completion.label()
21691            && matches!(
21692                completion.kind(),
21693                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21694            )
21695        {
21696            snippet_source = label;
21697        }
21698        match Snippet::parse(&snippet_source).log_err() {
21699            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21700            None => (None, completion.new_text.clone()),
21701        }
21702    } else {
21703        (None, completion.new_text.clone())
21704    };
21705
21706    let mut range_to_replace = {
21707        let replace_range = &completion.replace_range;
21708        if let CompletionSource::Lsp {
21709            insert_range: Some(insert_range),
21710            ..
21711        } = &completion.source
21712        {
21713            debug_assert_eq!(
21714                insert_range.start, replace_range.start,
21715                "insert_range and replace_range should start at the same position"
21716            );
21717            debug_assert!(
21718                insert_range
21719                    .start
21720                    .cmp(cursor_position, &buffer_snapshot)
21721                    .is_le(),
21722                "insert_range should start before or at cursor position"
21723            );
21724            debug_assert!(
21725                replace_range
21726                    .start
21727                    .cmp(cursor_position, &buffer_snapshot)
21728                    .is_le(),
21729                "replace_range should start before or at cursor position"
21730            );
21731
21732            let should_replace = match intent {
21733                CompletionIntent::CompleteWithInsert => false,
21734                CompletionIntent::CompleteWithReplace => true,
21735                CompletionIntent::Complete | CompletionIntent::Compose => {
21736                    let insert_mode =
21737                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21738                            .completions
21739                            .lsp_insert_mode;
21740                    match insert_mode {
21741                        LspInsertMode::Insert => false,
21742                        LspInsertMode::Replace => true,
21743                        LspInsertMode::ReplaceSubsequence => {
21744                            let mut text_to_replace = buffer.chars_for_range(
21745                                buffer.anchor_before(replace_range.start)
21746                                    ..buffer.anchor_after(replace_range.end),
21747                            );
21748                            let mut current_needle = text_to_replace.next();
21749                            for haystack_ch in completion.label.text.chars() {
21750                                if let Some(needle_ch) = current_needle
21751                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21752                                {
21753                                    current_needle = text_to_replace.next();
21754                                }
21755                            }
21756                            current_needle.is_none()
21757                        }
21758                        LspInsertMode::ReplaceSuffix => {
21759                            if replace_range
21760                                .end
21761                                .cmp(cursor_position, &buffer_snapshot)
21762                                .is_gt()
21763                            {
21764                                let range_after_cursor = *cursor_position..replace_range.end;
21765                                let text_after_cursor = buffer
21766                                    .text_for_range(
21767                                        buffer.anchor_before(range_after_cursor.start)
21768                                            ..buffer.anchor_after(range_after_cursor.end),
21769                                    )
21770                                    .collect::<String>()
21771                                    .to_ascii_lowercase();
21772                                completion
21773                                    .label
21774                                    .text
21775                                    .to_ascii_lowercase()
21776                                    .ends_with(&text_after_cursor)
21777                            } else {
21778                                true
21779                            }
21780                        }
21781                    }
21782                }
21783            };
21784
21785            if should_replace {
21786                replace_range.clone()
21787            } else {
21788                insert_range.clone()
21789            }
21790        } else {
21791            replace_range.clone()
21792        }
21793    };
21794
21795    if range_to_replace
21796        .end
21797        .cmp(cursor_position, &buffer_snapshot)
21798        .is_lt()
21799    {
21800        range_to_replace.end = *cursor_position;
21801    }
21802
21803    CompletionEdit {
21804        new_text,
21805        replace_range: range_to_replace.to_offset(buffer),
21806        snippet,
21807    }
21808}
21809
21810struct CompletionEdit {
21811    new_text: String,
21812    replace_range: Range<usize>,
21813    snippet: Option<Snippet>,
21814}
21815
21816fn insert_extra_newline_brackets(
21817    buffer: &MultiBufferSnapshot,
21818    range: Range<usize>,
21819    language: &language::LanguageScope,
21820) -> bool {
21821    let leading_whitespace_len = buffer
21822        .reversed_chars_at(range.start)
21823        .take_while(|c| c.is_whitespace() && *c != '\n')
21824        .map(|c| c.len_utf8())
21825        .sum::<usize>();
21826    let trailing_whitespace_len = buffer
21827        .chars_at(range.end)
21828        .take_while(|c| c.is_whitespace() && *c != '\n')
21829        .map(|c| c.len_utf8())
21830        .sum::<usize>();
21831    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21832
21833    language.brackets().any(|(pair, enabled)| {
21834        let pair_start = pair.start.trim_end();
21835        let pair_end = pair.end.trim_start();
21836
21837        enabled
21838            && pair.newline
21839            && buffer.contains_str_at(range.end, pair_end)
21840            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21841    })
21842}
21843
21844fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21845    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21846        [(buffer, range, _)] => (*buffer, range.clone()),
21847        _ => return false,
21848    };
21849    let pair = {
21850        let mut result: Option<BracketMatch> = None;
21851
21852        for pair in buffer
21853            .all_bracket_ranges(range.clone())
21854            .filter(move |pair| {
21855                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21856            })
21857        {
21858            let len = pair.close_range.end - pair.open_range.start;
21859
21860            if let Some(existing) = &result {
21861                let existing_len = existing.close_range.end - existing.open_range.start;
21862                if len > existing_len {
21863                    continue;
21864                }
21865            }
21866
21867            result = Some(pair);
21868        }
21869
21870        result
21871    };
21872    let Some(pair) = pair else {
21873        return false;
21874    };
21875    pair.newline_only
21876        && buffer
21877            .chars_for_range(pair.open_range.end..range.start)
21878            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21879            .all(|c| c.is_whitespace() && c != '\n')
21880}
21881
21882fn update_uncommitted_diff_for_buffer(
21883    editor: Entity<Editor>,
21884    project: &Entity<Project>,
21885    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21886    buffer: Entity<MultiBuffer>,
21887    cx: &mut App,
21888) -> Task<()> {
21889    let mut tasks = Vec::new();
21890    project.update(cx, |project, cx| {
21891        for buffer in buffers {
21892            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21893                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21894            }
21895        }
21896    });
21897    cx.spawn(async move |cx| {
21898        let diffs = future::join_all(tasks).await;
21899        if editor
21900            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21901            .unwrap_or(false)
21902        {
21903            return;
21904        }
21905
21906        buffer
21907            .update(cx, |buffer, cx| {
21908                for diff in diffs.into_iter().flatten() {
21909                    buffer.add_diff(diff, cx);
21910                }
21911            })
21912            .ok();
21913    })
21914}
21915
21916fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21917    let tab_size = tab_size.get() as usize;
21918    let mut width = offset;
21919
21920    for ch in text.chars() {
21921        width += if ch == '\t' {
21922            tab_size - (width % tab_size)
21923        } else {
21924            1
21925        };
21926    }
21927
21928    width - offset
21929}
21930
21931#[cfg(test)]
21932mod tests {
21933    use super::*;
21934
21935    #[test]
21936    fn test_string_size_with_expanded_tabs() {
21937        let nz = |val| NonZeroU32::new(val).unwrap();
21938        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21939        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21940        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21941        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21942        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21943        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21944        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21945        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21946    }
21947}
21948
21949/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21950struct WordBreakingTokenizer<'a> {
21951    input: &'a str,
21952}
21953
21954impl<'a> WordBreakingTokenizer<'a> {
21955    fn new(input: &'a str) -> Self {
21956        Self { input }
21957    }
21958}
21959
21960fn is_char_ideographic(ch: char) -> bool {
21961    use unicode_script::Script::*;
21962    use unicode_script::UnicodeScript;
21963    matches!(ch.script(), Han | Tangut | Yi)
21964}
21965
21966fn is_grapheme_ideographic(text: &str) -> bool {
21967    text.chars().any(is_char_ideographic)
21968}
21969
21970fn is_grapheme_whitespace(text: &str) -> bool {
21971    text.chars().any(|x| x.is_whitespace())
21972}
21973
21974fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21975    text.chars()
21976        .next()
21977        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21978}
21979
21980#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21981enum WordBreakToken<'a> {
21982    Word { token: &'a str, grapheme_len: usize },
21983    InlineWhitespace { token: &'a str, grapheme_len: usize },
21984    Newline,
21985}
21986
21987impl<'a> Iterator for WordBreakingTokenizer<'a> {
21988    /// Yields a span, the count of graphemes in the token, and whether it was
21989    /// whitespace. Note that it also breaks at word boundaries.
21990    type Item = WordBreakToken<'a>;
21991
21992    fn next(&mut self) -> Option<Self::Item> {
21993        use unicode_segmentation::UnicodeSegmentation;
21994        if self.input.is_empty() {
21995            return None;
21996        }
21997
21998        let mut iter = self.input.graphemes(true).peekable();
21999        let mut offset = 0;
22000        let mut grapheme_len = 0;
22001        if let Some(first_grapheme) = iter.next() {
22002            let is_newline = first_grapheme == "\n";
22003            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22004            offset += first_grapheme.len();
22005            grapheme_len += 1;
22006            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22007                if let Some(grapheme) = iter.peek().copied()
22008                    && should_stay_with_preceding_ideograph(grapheme)
22009                {
22010                    offset += grapheme.len();
22011                    grapheme_len += 1;
22012                }
22013            } else {
22014                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22015                let mut next_word_bound = words.peek().copied();
22016                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22017                    next_word_bound = words.next();
22018                }
22019                while let Some(grapheme) = iter.peek().copied() {
22020                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22021                        break;
22022                    };
22023                    if is_grapheme_whitespace(grapheme) != is_whitespace
22024                        || (grapheme == "\n") != is_newline
22025                    {
22026                        break;
22027                    };
22028                    offset += grapheme.len();
22029                    grapheme_len += 1;
22030                    iter.next();
22031                }
22032            }
22033            let token = &self.input[..offset];
22034            self.input = &self.input[offset..];
22035            if token == "\n" {
22036                Some(WordBreakToken::Newline)
22037            } else if is_whitespace {
22038                Some(WordBreakToken::InlineWhitespace {
22039                    token,
22040                    grapheme_len,
22041                })
22042            } else {
22043                Some(WordBreakToken::Word {
22044                    token,
22045                    grapheme_len,
22046                })
22047            }
22048        } else {
22049            None
22050        }
22051    }
22052}
22053
22054#[test]
22055fn test_word_breaking_tokenizer() {
22056    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22057        ("", &[]),
22058        ("  ", &[whitespace("  ", 2)]),
22059        ("Ʒ", &[word("Ʒ", 1)]),
22060        ("Ǽ", &[word("Ǽ", 1)]),
22061        ("", &[word("", 1)]),
22062        ("⋑⋑", &[word("⋑⋑", 2)]),
22063        (
22064            "原理,进而",
22065            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22066        ),
22067        (
22068            "hello world",
22069            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22070        ),
22071        (
22072            "hello, world",
22073            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22074        ),
22075        (
22076            "  hello world",
22077            &[
22078                whitespace("  ", 2),
22079                word("hello", 5),
22080                whitespace(" ", 1),
22081                word("world", 5),
22082            ],
22083        ),
22084        (
22085            "这是什么 \n 钢笔",
22086            &[
22087                word("", 1),
22088                word("", 1),
22089                word("", 1),
22090                word("", 1),
22091                whitespace(" ", 1),
22092                newline(),
22093                whitespace(" ", 1),
22094                word("", 1),
22095                word("", 1),
22096            ],
22097        ),
22098        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22099    ];
22100
22101    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22102        WordBreakToken::Word {
22103            token,
22104            grapheme_len,
22105        }
22106    }
22107
22108    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22109        WordBreakToken::InlineWhitespace {
22110            token,
22111            grapheme_len,
22112        }
22113    }
22114
22115    fn newline() -> WordBreakToken<'static> {
22116        WordBreakToken::Newline
22117    }
22118
22119    for (input, result) in tests {
22120        assert_eq!(
22121            WordBreakingTokenizer::new(input)
22122                .collect::<Vec<_>>()
22123                .as_slice(),
22124            *result,
22125        );
22126    }
22127}
22128
22129fn wrap_with_prefix(
22130    first_line_prefix: String,
22131    subsequent_lines_prefix: String,
22132    unwrapped_text: String,
22133    wrap_column: usize,
22134    tab_size: NonZeroU32,
22135    preserve_existing_whitespace: bool,
22136) -> String {
22137    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22138    let subsequent_lines_prefix_len =
22139        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22140    let mut wrapped_text = String::new();
22141    let mut current_line = first_line_prefix;
22142    let mut is_first_line = true;
22143
22144    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22145    let mut current_line_len = first_line_prefix_len;
22146    let mut in_whitespace = false;
22147    for token in tokenizer {
22148        let have_preceding_whitespace = in_whitespace;
22149        match token {
22150            WordBreakToken::Word {
22151                token,
22152                grapheme_len,
22153            } => {
22154                in_whitespace = false;
22155                let current_prefix_len = if is_first_line {
22156                    first_line_prefix_len
22157                } else {
22158                    subsequent_lines_prefix_len
22159                };
22160                if current_line_len + grapheme_len > wrap_column
22161                    && current_line_len != current_prefix_len
22162                {
22163                    wrapped_text.push_str(current_line.trim_end());
22164                    wrapped_text.push('\n');
22165                    is_first_line = false;
22166                    current_line = subsequent_lines_prefix.clone();
22167                    current_line_len = subsequent_lines_prefix_len;
22168                }
22169                current_line.push_str(token);
22170                current_line_len += grapheme_len;
22171            }
22172            WordBreakToken::InlineWhitespace {
22173                mut token,
22174                mut grapheme_len,
22175            } => {
22176                in_whitespace = true;
22177                if have_preceding_whitespace && !preserve_existing_whitespace {
22178                    continue;
22179                }
22180                if !preserve_existing_whitespace {
22181                    token = " ";
22182                    grapheme_len = 1;
22183                }
22184                let current_prefix_len = if is_first_line {
22185                    first_line_prefix_len
22186                } else {
22187                    subsequent_lines_prefix_len
22188                };
22189                if current_line_len + grapheme_len > wrap_column {
22190                    wrapped_text.push_str(current_line.trim_end());
22191                    wrapped_text.push('\n');
22192                    is_first_line = false;
22193                    current_line = subsequent_lines_prefix.clone();
22194                    current_line_len = subsequent_lines_prefix_len;
22195                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22196                    current_line.push_str(token);
22197                    current_line_len += grapheme_len;
22198                }
22199            }
22200            WordBreakToken::Newline => {
22201                in_whitespace = true;
22202                let current_prefix_len = if is_first_line {
22203                    first_line_prefix_len
22204                } else {
22205                    subsequent_lines_prefix_len
22206                };
22207                if preserve_existing_whitespace {
22208                    wrapped_text.push_str(current_line.trim_end());
22209                    wrapped_text.push('\n');
22210                    is_first_line = false;
22211                    current_line = subsequent_lines_prefix.clone();
22212                    current_line_len = subsequent_lines_prefix_len;
22213                } else if have_preceding_whitespace {
22214                    continue;
22215                } else if current_line_len + 1 > wrap_column
22216                    && current_line_len != current_prefix_len
22217                {
22218                    wrapped_text.push_str(current_line.trim_end());
22219                    wrapped_text.push('\n');
22220                    is_first_line = false;
22221                    current_line = subsequent_lines_prefix.clone();
22222                    current_line_len = subsequent_lines_prefix_len;
22223                } else if current_line_len != current_prefix_len {
22224                    current_line.push(' ');
22225                    current_line_len += 1;
22226                }
22227            }
22228        }
22229    }
22230
22231    if !current_line.is_empty() {
22232        wrapped_text.push_str(&current_line);
22233    }
22234    wrapped_text
22235}
22236
22237#[test]
22238fn test_wrap_with_prefix() {
22239    assert_eq!(
22240        wrap_with_prefix(
22241            "# ".to_string(),
22242            "# ".to_string(),
22243            "abcdefg".to_string(),
22244            4,
22245            NonZeroU32::new(4).unwrap(),
22246            false,
22247        ),
22248        "# abcdefg"
22249    );
22250    assert_eq!(
22251        wrap_with_prefix(
22252            "".to_string(),
22253            "".to_string(),
22254            "\thello world".to_string(),
22255            8,
22256            NonZeroU32::new(4).unwrap(),
22257            false,
22258        ),
22259        "hello\nworld"
22260    );
22261    assert_eq!(
22262        wrap_with_prefix(
22263            "// ".to_string(),
22264            "// ".to_string(),
22265            "xx \nyy zz aa bb cc".to_string(),
22266            12,
22267            NonZeroU32::new(4).unwrap(),
22268            false,
22269        ),
22270        "// xx yy zz\n// aa bb cc"
22271    );
22272    assert_eq!(
22273        wrap_with_prefix(
22274            String::new(),
22275            String::new(),
22276            "这是什么 \n 钢笔".to_string(),
22277            3,
22278            NonZeroU32::new(4).unwrap(),
22279            false,
22280        ),
22281        "这是什\n么 钢\n"
22282    );
22283}
22284
22285pub trait CollaborationHub {
22286    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22287    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22288    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22289}
22290
22291impl CollaborationHub for Entity<Project> {
22292    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22293        self.read(cx).collaborators()
22294    }
22295
22296    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22297        self.read(cx).user_store().read(cx).participant_indices()
22298    }
22299
22300    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22301        let this = self.read(cx);
22302        let user_ids = this.collaborators().values().map(|c| c.user_id);
22303        this.user_store().read(cx).participant_names(user_ids, cx)
22304    }
22305}
22306
22307pub trait SemanticsProvider {
22308    fn hover(
22309        &self,
22310        buffer: &Entity<Buffer>,
22311        position: text::Anchor,
22312        cx: &mut App,
22313    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22314
22315    fn inline_values(
22316        &self,
22317        buffer_handle: Entity<Buffer>,
22318        range: Range<text::Anchor>,
22319        cx: &mut App,
22320    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22321
22322    fn inlay_hints(
22323        &self,
22324        buffer_handle: Entity<Buffer>,
22325        range: Range<text::Anchor>,
22326        cx: &mut App,
22327    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22328
22329    fn resolve_inlay_hint(
22330        &self,
22331        hint: InlayHint,
22332        buffer_handle: Entity<Buffer>,
22333        server_id: LanguageServerId,
22334        cx: &mut App,
22335    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22336
22337    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22338
22339    fn document_highlights(
22340        &self,
22341        buffer: &Entity<Buffer>,
22342        position: text::Anchor,
22343        cx: &mut App,
22344    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22345
22346    fn definitions(
22347        &self,
22348        buffer: &Entity<Buffer>,
22349        position: text::Anchor,
22350        kind: GotoDefinitionKind,
22351        cx: &mut App,
22352    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22353
22354    fn range_for_rename(
22355        &self,
22356        buffer: &Entity<Buffer>,
22357        position: text::Anchor,
22358        cx: &mut App,
22359    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22360
22361    fn perform_rename(
22362        &self,
22363        buffer: &Entity<Buffer>,
22364        position: text::Anchor,
22365        new_name: String,
22366        cx: &mut App,
22367    ) -> Option<Task<Result<ProjectTransaction>>>;
22368}
22369
22370pub trait CompletionProvider {
22371    fn completions(
22372        &self,
22373        excerpt_id: ExcerptId,
22374        buffer: &Entity<Buffer>,
22375        buffer_position: text::Anchor,
22376        trigger: CompletionContext,
22377        window: &mut Window,
22378        cx: &mut Context<Editor>,
22379    ) -> Task<Result<Vec<CompletionResponse>>>;
22380
22381    fn resolve_completions(
22382        &self,
22383        _buffer: Entity<Buffer>,
22384        _completion_indices: Vec<usize>,
22385        _completions: Rc<RefCell<Box<[Completion]>>>,
22386        _cx: &mut Context<Editor>,
22387    ) -> Task<Result<bool>> {
22388        Task::ready(Ok(false))
22389    }
22390
22391    fn apply_additional_edits_for_completion(
22392        &self,
22393        _buffer: Entity<Buffer>,
22394        _completions: Rc<RefCell<Box<[Completion]>>>,
22395        _completion_index: usize,
22396        _push_to_history: bool,
22397        _cx: &mut Context<Editor>,
22398    ) -> Task<Result<Option<language::Transaction>>> {
22399        Task::ready(Ok(None))
22400    }
22401
22402    fn is_completion_trigger(
22403        &self,
22404        buffer: &Entity<Buffer>,
22405        position: language::Anchor,
22406        text: &str,
22407        trigger_in_words: bool,
22408        menu_is_open: bool,
22409        cx: &mut Context<Editor>,
22410    ) -> bool;
22411
22412    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22413
22414    fn sort_completions(&self) -> bool {
22415        true
22416    }
22417
22418    fn filter_completions(&self) -> bool {
22419        true
22420    }
22421}
22422
22423pub trait CodeActionProvider {
22424    fn id(&self) -> Arc<str>;
22425
22426    fn code_actions(
22427        &self,
22428        buffer: &Entity<Buffer>,
22429        range: Range<text::Anchor>,
22430        window: &mut Window,
22431        cx: &mut App,
22432    ) -> Task<Result<Vec<CodeAction>>>;
22433
22434    fn apply_code_action(
22435        &self,
22436        buffer_handle: Entity<Buffer>,
22437        action: CodeAction,
22438        excerpt_id: ExcerptId,
22439        push_to_history: bool,
22440        window: &mut Window,
22441        cx: &mut App,
22442    ) -> Task<Result<ProjectTransaction>>;
22443}
22444
22445impl CodeActionProvider for Entity<Project> {
22446    fn id(&self) -> Arc<str> {
22447        "project".into()
22448    }
22449
22450    fn code_actions(
22451        &self,
22452        buffer: &Entity<Buffer>,
22453        range: Range<text::Anchor>,
22454        _window: &mut Window,
22455        cx: &mut App,
22456    ) -> Task<Result<Vec<CodeAction>>> {
22457        self.update(cx, |project, cx| {
22458            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22459            let code_actions = project.code_actions(buffer, range, None, cx);
22460            cx.background_spawn(async move {
22461                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22462                Ok(code_lens_actions
22463                    .context("code lens fetch")?
22464                    .into_iter()
22465                    .flatten()
22466                    .chain(
22467                        code_actions
22468                            .context("code action fetch")?
22469                            .into_iter()
22470                            .flatten(),
22471                    )
22472                    .collect())
22473            })
22474        })
22475    }
22476
22477    fn apply_code_action(
22478        &self,
22479        buffer_handle: Entity<Buffer>,
22480        action: CodeAction,
22481        _excerpt_id: ExcerptId,
22482        push_to_history: bool,
22483        _window: &mut Window,
22484        cx: &mut App,
22485    ) -> Task<Result<ProjectTransaction>> {
22486        self.update(cx, |project, cx| {
22487            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22488        })
22489    }
22490}
22491
22492fn snippet_completions(
22493    project: &Project,
22494    buffer: &Entity<Buffer>,
22495    buffer_position: text::Anchor,
22496    cx: &mut App,
22497) -> Task<Result<CompletionResponse>> {
22498    let languages = buffer.read(cx).languages_at(buffer_position);
22499    let snippet_store = project.snippets().read(cx);
22500
22501    let scopes: Vec<_> = languages
22502        .iter()
22503        .filter_map(|language| {
22504            let language_name = language.lsp_id();
22505            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22506
22507            if snippets.is_empty() {
22508                None
22509            } else {
22510                Some((language.default_scope(), snippets))
22511            }
22512        })
22513        .collect();
22514
22515    if scopes.is_empty() {
22516        return Task::ready(Ok(CompletionResponse {
22517            completions: vec![],
22518            display_options: CompletionDisplayOptions::default(),
22519            is_incomplete: false,
22520        }));
22521    }
22522
22523    let snapshot = buffer.read(cx).text_snapshot();
22524    let chars: String = snapshot
22525        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22526        .collect();
22527    let executor = cx.background_executor().clone();
22528
22529    cx.background_spawn(async move {
22530        let mut is_incomplete = false;
22531        let mut completions: Vec<Completion> = Vec::new();
22532        for (scope, snippets) in scopes.into_iter() {
22533            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22534            let mut last_word = chars
22535                .chars()
22536                .take_while(|c| classifier.is_word(*c))
22537                .collect::<String>();
22538            last_word = last_word.chars().rev().collect();
22539
22540            if last_word.is_empty() {
22541                return Ok(CompletionResponse {
22542                    completions: vec![],
22543                    display_options: CompletionDisplayOptions::default(),
22544                    is_incomplete: true,
22545                });
22546            }
22547
22548            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22549            let to_lsp = |point: &text::Anchor| {
22550                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22551                point_to_lsp(end)
22552            };
22553            let lsp_end = to_lsp(&buffer_position);
22554
22555            let candidates = snippets
22556                .iter()
22557                .enumerate()
22558                .flat_map(|(ix, snippet)| {
22559                    snippet
22560                        .prefix
22561                        .iter()
22562                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22563                })
22564                .collect::<Vec<StringMatchCandidate>>();
22565
22566            const MAX_RESULTS: usize = 100;
22567            let mut matches = fuzzy::match_strings(
22568                &candidates,
22569                &last_word,
22570                last_word.chars().any(|c| c.is_uppercase()),
22571                true,
22572                MAX_RESULTS,
22573                &Default::default(),
22574                executor.clone(),
22575            )
22576            .await;
22577
22578            if matches.len() >= MAX_RESULTS {
22579                is_incomplete = true;
22580            }
22581
22582            // Remove all candidates where the query's start does not match the start of any word in the candidate
22583            if let Some(query_start) = last_word.chars().next() {
22584                matches.retain(|string_match| {
22585                    split_words(&string_match.string).any(|word| {
22586                        // Check that the first codepoint of the word as lowercase matches the first
22587                        // codepoint of the query as lowercase
22588                        word.chars()
22589                            .flat_map(|codepoint| codepoint.to_lowercase())
22590                            .zip(query_start.to_lowercase())
22591                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22592                    })
22593                });
22594            }
22595
22596            let matched_strings = matches
22597                .into_iter()
22598                .map(|m| m.string)
22599                .collect::<HashSet<_>>();
22600
22601            completions.extend(snippets.iter().filter_map(|snippet| {
22602                let matching_prefix = snippet
22603                    .prefix
22604                    .iter()
22605                    .find(|prefix| matched_strings.contains(*prefix))?;
22606                let start = as_offset - last_word.len();
22607                let start = snapshot.anchor_before(start);
22608                let range = start..buffer_position;
22609                let lsp_start = to_lsp(&start);
22610                let lsp_range = lsp::Range {
22611                    start: lsp_start,
22612                    end: lsp_end,
22613                };
22614                Some(Completion {
22615                    replace_range: range,
22616                    new_text: snippet.body.clone(),
22617                    source: CompletionSource::Lsp {
22618                        insert_range: None,
22619                        server_id: LanguageServerId(usize::MAX),
22620                        resolved: true,
22621                        lsp_completion: Box::new(lsp::CompletionItem {
22622                            label: snippet.prefix.first().unwrap().clone(),
22623                            kind: Some(CompletionItemKind::SNIPPET),
22624                            label_details: snippet.description.as_ref().map(|description| {
22625                                lsp::CompletionItemLabelDetails {
22626                                    detail: Some(description.clone()),
22627                                    description: None,
22628                                }
22629                            }),
22630                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22631                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22632                                lsp::InsertReplaceEdit {
22633                                    new_text: snippet.body.clone(),
22634                                    insert: lsp_range,
22635                                    replace: lsp_range,
22636                                },
22637                            )),
22638                            filter_text: Some(snippet.body.clone()),
22639                            sort_text: Some(char::MAX.to_string()),
22640                            ..lsp::CompletionItem::default()
22641                        }),
22642                        lsp_defaults: None,
22643                    },
22644                    label: CodeLabel {
22645                        text: matching_prefix.clone(),
22646                        runs: Vec::new(),
22647                        filter_range: 0..matching_prefix.len(),
22648                    },
22649                    icon_path: None,
22650                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22651                        single_line: snippet.name.clone().into(),
22652                        plain_text: snippet
22653                            .description
22654                            .clone()
22655                            .map(|description| description.into()),
22656                    }),
22657                    insert_text_mode: None,
22658                    confirm: None,
22659                })
22660            }))
22661        }
22662
22663        Ok(CompletionResponse {
22664            completions,
22665            display_options: CompletionDisplayOptions::default(),
22666            is_incomplete,
22667        })
22668    })
22669}
22670
22671impl CompletionProvider for Entity<Project> {
22672    fn completions(
22673        &self,
22674        _excerpt_id: ExcerptId,
22675        buffer: &Entity<Buffer>,
22676        buffer_position: text::Anchor,
22677        options: CompletionContext,
22678        _window: &mut Window,
22679        cx: &mut Context<Editor>,
22680    ) -> Task<Result<Vec<CompletionResponse>>> {
22681        self.update(cx, |project, cx| {
22682            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22683            let project_completions = project.completions(buffer, buffer_position, options, cx);
22684            cx.background_spawn(async move {
22685                let mut responses = project_completions.await?;
22686                let snippets = snippets.await?;
22687                if !snippets.completions.is_empty() {
22688                    responses.push(snippets);
22689                }
22690                Ok(responses)
22691            })
22692        })
22693    }
22694
22695    fn resolve_completions(
22696        &self,
22697        buffer: Entity<Buffer>,
22698        completion_indices: Vec<usize>,
22699        completions: Rc<RefCell<Box<[Completion]>>>,
22700        cx: &mut Context<Editor>,
22701    ) -> Task<Result<bool>> {
22702        self.update(cx, |project, cx| {
22703            project.lsp_store().update(cx, |lsp_store, cx| {
22704                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22705            })
22706        })
22707    }
22708
22709    fn apply_additional_edits_for_completion(
22710        &self,
22711        buffer: Entity<Buffer>,
22712        completions: Rc<RefCell<Box<[Completion]>>>,
22713        completion_index: usize,
22714        push_to_history: bool,
22715        cx: &mut Context<Editor>,
22716    ) -> Task<Result<Option<language::Transaction>>> {
22717        self.update(cx, |project, cx| {
22718            project.lsp_store().update(cx, |lsp_store, cx| {
22719                lsp_store.apply_additional_edits_for_completion(
22720                    buffer,
22721                    completions,
22722                    completion_index,
22723                    push_to_history,
22724                    cx,
22725                )
22726            })
22727        })
22728    }
22729
22730    fn is_completion_trigger(
22731        &self,
22732        buffer: &Entity<Buffer>,
22733        position: language::Anchor,
22734        text: &str,
22735        trigger_in_words: bool,
22736        menu_is_open: bool,
22737        cx: &mut Context<Editor>,
22738    ) -> bool {
22739        let mut chars = text.chars();
22740        let char = if let Some(char) = chars.next() {
22741            char
22742        } else {
22743            return false;
22744        };
22745        if chars.next().is_some() {
22746            return false;
22747        }
22748
22749        let buffer = buffer.read(cx);
22750        let snapshot = buffer.snapshot();
22751        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22752            return false;
22753        }
22754        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22755        if trigger_in_words && classifier.is_word(char) {
22756            return true;
22757        }
22758
22759        buffer.completion_triggers().contains(text)
22760    }
22761}
22762
22763impl SemanticsProvider for Entity<Project> {
22764    fn hover(
22765        &self,
22766        buffer: &Entity<Buffer>,
22767        position: text::Anchor,
22768        cx: &mut App,
22769    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22770        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22771    }
22772
22773    fn document_highlights(
22774        &self,
22775        buffer: &Entity<Buffer>,
22776        position: text::Anchor,
22777        cx: &mut App,
22778    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22779        Some(self.update(cx, |project, cx| {
22780            project.document_highlights(buffer, position, cx)
22781        }))
22782    }
22783
22784    fn definitions(
22785        &self,
22786        buffer: &Entity<Buffer>,
22787        position: text::Anchor,
22788        kind: GotoDefinitionKind,
22789        cx: &mut App,
22790    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22791        Some(self.update(cx, |project, cx| match kind {
22792            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22793            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22794            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22795            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22796        }))
22797    }
22798
22799    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22800        self.update(cx, |project, cx| {
22801            if project
22802                .active_debug_session(cx)
22803                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22804            {
22805                return true;
22806            }
22807
22808            buffer.update(cx, |buffer, cx| {
22809                project.any_language_server_supports_inlay_hints(buffer, cx)
22810            })
22811        })
22812    }
22813
22814    fn inline_values(
22815        &self,
22816        buffer_handle: Entity<Buffer>,
22817        range: Range<text::Anchor>,
22818        cx: &mut App,
22819    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22820        self.update(cx, |project, cx| {
22821            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22822
22823            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22824        })
22825    }
22826
22827    fn inlay_hints(
22828        &self,
22829        buffer_handle: Entity<Buffer>,
22830        range: Range<text::Anchor>,
22831        cx: &mut App,
22832    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22833        Some(self.update(cx, |project, cx| {
22834            project.inlay_hints(buffer_handle, range, cx)
22835        }))
22836    }
22837
22838    fn resolve_inlay_hint(
22839        &self,
22840        hint: InlayHint,
22841        buffer_handle: Entity<Buffer>,
22842        server_id: LanguageServerId,
22843        cx: &mut App,
22844    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22845        Some(self.update(cx, |project, cx| {
22846            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22847        }))
22848    }
22849
22850    fn range_for_rename(
22851        &self,
22852        buffer: &Entity<Buffer>,
22853        position: text::Anchor,
22854        cx: &mut App,
22855    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22856        Some(self.update(cx, |project, cx| {
22857            let buffer = buffer.clone();
22858            let task = project.prepare_rename(buffer.clone(), position, cx);
22859            cx.spawn(async move |_, cx| {
22860                Ok(match task.await? {
22861                    PrepareRenameResponse::Success(range) => Some(range),
22862                    PrepareRenameResponse::InvalidPosition => None,
22863                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22864                        // Fallback on using TreeSitter info to determine identifier range
22865                        buffer.read_with(cx, |buffer, _| {
22866                            let snapshot = buffer.snapshot();
22867                            let (range, kind) = snapshot.surrounding_word(position, false);
22868                            if kind != Some(CharKind::Word) {
22869                                return None;
22870                            }
22871                            Some(
22872                                snapshot.anchor_before(range.start)
22873                                    ..snapshot.anchor_after(range.end),
22874                            )
22875                        })?
22876                    }
22877                })
22878            })
22879        }))
22880    }
22881
22882    fn perform_rename(
22883        &self,
22884        buffer: &Entity<Buffer>,
22885        position: text::Anchor,
22886        new_name: String,
22887        cx: &mut App,
22888    ) -> Option<Task<Result<ProjectTransaction>>> {
22889        Some(self.update(cx, |project, cx| {
22890            project.perform_rename(buffer.clone(), position, new_name, cx)
22891        }))
22892    }
22893}
22894
22895fn inlay_hint_settings(
22896    location: Anchor,
22897    snapshot: &MultiBufferSnapshot,
22898    cx: &mut Context<Editor>,
22899) -> InlayHintSettings {
22900    let file = snapshot.file_at(location);
22901    let language = snapshot.language_at(location).map(|l| l.name());
22902    language_settings(language, file, cx).inlay_hints.clone()
22903}
22904
22905fn consume_contiguous_rows(
22906    contiguous_row_selections: &mut Vec<Selection<Point>>,
22907    selection: &Selection<Point>,
22908    display_map: &DisplaySnapshot,
22909    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22910) -> (MultiBufferRow, MultiBufferRow) {
22911    contiguous_row_selections.push(selection.clone());
22912    let start_row = starting_row(selection, display_map);
22913    let mut end_row = ending_row(selection, display_map);
22914
22915    while let Some(next_selection) = selections.peek() {
22916        if next_selection.start.row <= end_row.0 {
22917            end_row = ending_row(next_selection, display_map);
22918            contiguous_row_selections.push(selections.next().unwrap().clone());
22919        } else {
22920            break;
22921        }
22922    }
22923    (start_row, end_row)
22924}
22925
22926fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22927    if selection.start.column > 0 {
22928        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22929    } else {
22930        MultiBufferRow(selection.start.row)
22931    }
22932}
22933
22934fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22935    if next_selection.end.column > 0 || next_selection.is_empty() {
22936        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22937    } else {
22938        MultiBufferRow(next_selection.end.row)
22939    }
22940}
22941
22942impl EditorSnapshot {
22943    pub fn remote_selections_in_range<'a>(
22944        &'a self,
22945        range: &'a Range<Anchor>,
22946        collaboration_hub: &dyn CollaborationHub,
22947        cx: &'a App,
22948    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22949        let participant_names = collaboration_hub.user_names(cx);
22950        let participant_indices = collaboration_hub.user_participant_indices(cx);
22951        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22952        let collaborators_by_replica_id = collaborators_by_peer_id
22953            .values()
22954            .map(|collaborator| (collaborator.replica_id, collaborator))
22955            .collect::<HashMap<_, _>>();
22956        self.buffer_snapshot
22957            .selections_in_range(range, false)
22958            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22959                if replica_id == AGENT_REPLICA_ID {
22960                    Some(RemoteSelection {
22961                        replica_id,
22962                        selection,
22963                        cursor_shape,
22964                        line_mode,
22965                        collaborator_id: CollaboratorId::Agent,
22966                        user_name: Some("Agent".into()),
22967                        color: cx.theme().players().agent(),
22968                    })
22969                } else {
22970                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22971                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22972                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22973                    Some(RemoteSelection {
22974                        replica_id,
22975                        selection,
22976                        cursor_shape,
22977                        line_mode,
22978                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22979                        user_name,
22980                        color: if let Some(index) = participant_index {
22981                            cx.theme().players().color_for_participant(index.0)
22982                        } else {
22983                            cx.theme().players().absent()
22984                        },
22985                    })
22986                }
22987            })
22988    }
22989
22990    pub fn hunks_for_ranges(
22991        &self,
22992        ranges: impl IntoIterator<Item = Range<Point>>,
22993    ) -> Vec<MultiBufferDiffHunk> {
22994        let mut hunks = Vec::new();
22995        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22996            HashMap::default();
22997        for query_range in ranges {
22998            let query_rows =
22999                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23000            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23001                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23002            ) {
23003                // Include deleted hunks that are adjacent to the query range, because
23004                // otherwise they would be missed.
23005                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23006                if hunk.status().is_deleted() {
23007                    intersects_range |= hunk.row_range.start == query_rows.end;
23008                    intersects_range |= hunk.row_range.end == query_rows.start;
23009                }
23010                if intersects_range {
23011                    if !processed_buffer_rows
23012                        .entry(hunk.buffer_id)
23013                        .or_default()
23014                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23015                    {
23016                        continue;
23017                    }
23018                    hunks.push(hunk);
23019                }
23020            }
23021        }
23022
23023        hunks
23024    }
23025
23026    fn display_diff_hunks_for_rows<'a>(
23027        &'a self,
23028        display_rows: Range<DisplayRow>,
23029        folded_buffers: &'a HashSet<BufferId>,
23030    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23031        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23032        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23033
23034        self.buffer_snapshot
23035            .diff_hunks_in_range(buffer_start..buffer_end)
23036            .filter_map(|hunk| {
23037                if folded_buffers.contains(&hunk.buffer_id) {
23038                    return None;
23039                }
23040
23041                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23042                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23043
23044                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23045                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23046
23047                let display_hunk = if hunk_display_start.column() != 0 {
23048                    DisplayDiffHunk::Folded {
23049                        display_row: hunk_display_start.row(),
23050                    }
23051                } else {
23052                    let mut end_row = hunk_display_end.row();
23053                    if hunk_display_end.column() > 0 {
23054                        end_row.0 += 1;
23055                    }
23056                    let is_created_file = hunk.is_created_file();
23057                    DisplayDiffHunk::Unfolded {
23058                        status: hunk.status(),
23059                        diff_base_byte_range: hunk.diff_base_byte_range,
23060                        display_row_range: hunk_display_start.row()..end_row,
23061                        multi_buffer_range: Anchor::range_in_buffer(
23062                            hunk.excerpt_id,
23063                            hunk.buffer_id,
23064                            hunk.buffer_range,
23065                        ),
23066                        is_created_file,
23067                    }
23068                };
23069
23070                Some(display_hunk)
23071            })
23072    }
23073
23074    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23075        self.display_snapshot.buffer_snapshot.language_at(position)
23076    }
23077
23078    pub fn is_focused(&self) -> bool {
23079        self.is_focused
23080    }
23081
23082    pub fn placeholder_text(&self) -> Option<String> {
23083        self.placeholder_display_snapshot
23084            .as_ref()
23085            .map(|display_map| display_map.text())
23086    }
23087
23088    pub fn scroll_position(&self) -> gpui::Point<f32> {
23089        self.scroll_anchor.scroll_position(&self.display_snapshot)
23090    }
23091
23092    fn gutter_dimensions(
23093        &self,
23094        font_id: FontId,
23095        font_size: Pixels,
23096        max_line_number_width: Pixels,
23097        cx: &App,
23098    ) -> Option<GutterDimensions> {
23099        if !self.show_gutter {
23100            return None;
23101        }
23102
23103        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23104        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23105
23106        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23107            matches!(
23108                ProjectSettings::get_global(cx).git.git_gutter,
23109                GitGutterSetting::TrackedFiles
23110            )
23111        });
23112        let gutter_settings = EditorSettings::get_global(cx).gutter;
23113        let show_line_numbers = self
23114            .show_line_numbers
23115            .unwrap_or(gutter_settings.line_numbers);
23116        let line_gutter_width = if show_line_numbers {
23117            // Avoid flicker-like gutter resizes when the line number gains another digit by
23118            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23119            let min_width_for_number_on_gutter =
23120                ch_advance * gutter_settings.min_line_number_digits as f32;
23121            max_line_number_width.max(min_width_for_number_on_gutter)
23122        } else {
23123            0.0.into()
23124        };
23125
23126        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23127        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23128
23129        let git_blame_entries_width =
23130            self.git_blame_gutter_max_author_length
23131                .map(|max_author_length| {
23132                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23133                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23134
23135                    /// The number of characters to dedicate to gaps and margins.
23136                    const SPACING_WIDTH: usize = 4;
23137
23138                    let max_char_count = max_author_length.min(renderer.max_author_length())
23139                        + ::git::SHORT_SHA_LENGTH
23140                        + MAX_RELATIVE_TIMESTAMP.len()
23141                        + SPACING_WIDTH;
23142
23143                    ch_advance * max_char_count
23144                });
23145
23146        let is_singleton = self.buffer_snapshot.is_singleton();
23147
23148        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23149        left_padding += if !is_singleton {
23150            ch_width * 4.0
23151        } else if show_runnables || show_breakpoints {
23152            ch_width * 3.0
23153        } else if show_git_gutter && show_line_numbers {
23154            ch_width * 2.0
23155        } else if show_git_gutter || show_line_numbers {
23156            ch_width
23157        } else {
23158            px(0.)
23159        };
23160
23161        let shows_folds = is_singleton && gutter_settings.folds;
23162
23163        let right_padding = if shows_folds && show_line_numbers {
23164            ch_width * 4.0
23165        } else if shows_folds || (!is_singleton && show_line_numbers) {
23166            ch_width * 3.0
23167        } else if show_line_numbers {
23168            ch_width
23169        } else {
23170            px(0.)
23171        };
23172
23173        Some(GutterDimensions {
23174            left_padding,
23175            right_padding,
23176            width: line_gutter_width + left_padding + right_padding,
23177            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23178            git_blame_entries_width,
23179        })
23180    }
23181
23182    pub fn render_crease_toggle(
23183        &self,
23184        buffer_row: MultiBufferRow,
23185        row_contains_cursor: bool,
23186        editor: Entity<Editor>,
23187        window: &mut Window,
23188        cx: &mut App,
23189    ) -> Option<AnyElement> {
23190        let folded = self.is_line_folded(buffer_row);
23191        let mut is_foldable = false;
23192
23193        if let Some(crease) = self
23194            .crease_snapshot
23195            .query_row(buffer_row, &self.buffer_snapshot)
23196        {
23197            is_foldable = true;
23198            match crease {
23199                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23200                    if let Some(render_toggle) = render_toggle {
23201                        let toggle_callback =
23202                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23203                                if folded {
23204                                    editor.update(cx, |editor, cx| {
23205                                        editor.fold_at(buffer_row, window, cx)
23206                                    });
23207                                } else {
23208                                    editor.update(cx, |editor, cx| {
23209                                        editor.unfold_at(buffer_row, window, cx)
23210                                    });
23211                                }
23212                            });
23213                        return Some((render_toggle)(
23214                            buffer_row,
23215                            folded,
23216                            toggle_callback,
23217                            window,
23218                            cx,
23219                        ));
23220                    }
23221                }
23222            }
23223        }
23224
23225        is_foldable |= self.starts_indent(buffer_row);
23226
23227        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23228            Some(
23229                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23230                    .toggle_state(folded)
23231                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23232                        if folded {
23233                            this.unfold_at(buffer_row, window, cx);
23234                        } else {
23235                            this.fold_at(buffer_row, window, cx);
23236                        }
23237                    }))
23238                    .into_any_element(),
23239            )
23240        } else {
23241            None
23242        }
23243    }
23244
23245    pub fn render_crease_trailer(
23246        &self,
23247        buffer_row: MultiBufferRow,
23248        window: &mut Window,
23249        cx: &mut App,
23250    ) -> Option<AnyElement> {
23251        let folded = self.is_line_folded(buffer_row);
23252        if let Crease::Inline { render_trailer, .. } = self
23253            .crease_snapshot
23254            .query_row(buffer_row, &self.buffer_snapshot)?
23255        {
23256            let render_trailer = render_trailer.as_ref()?;
23257            Some(render_trailer(buffer_row, folded, window, cx))
23258        } else {
23259            None
23260        }
23261    }
23262}
23263
23264impl Deref for EditorSnapshot {
23265    type Target = DisplaySnapshot;
23266
23267    fn deref(&self) -> &Self::Target {
23268        &self.display_snapshot
23269    }
23270}
23271
23272#[derive(Clone, Debug, PartialEq, Eq)]
23273pub enum EditorEvent {
23274    InputIgnored {
23275        text: Arc<str>,
23276    },
23277    InputHandled {
23278        utf16_range_to_replace: Option<Range<isize>>,
23279        text: Arc<str>,
23280    },
23281    ExcerptsAdded {
23282        buffer: Entity<Buffer>,
23283        predecessor: ExcerptId,
23284        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23285    },
23286    ExcerptsRemoved {
23287        ids: Vec<ExcerptId>,
23288        removed_buffer_ids: Vec<BufferId>,
23289    },
23290    BufferFoldToggled {
23291        ids: Vec<ExcerptId>,
23292        folded: bool,
23293    },
23294    ExcerptsEdited {
23295        ids: Vec<ExcerptId>,
23296    },
23297    ExcerptsExpanded {
23298        ids: Vec<ExcerptId>,
23299    },
23300    BufferEdited,
23301    Edited {
23302        transaction_id: clock::Lamport,
23303    },
23304    Reparsed(BufferId),
23305    Focused,
23306    FocusedIn,
23307    Blurred,
23308    DirtyChanged,
23309    Saved,
23310    TitleChanged,
23311    SelectionsChanged {
23312        local: bool,
23313    },
23314    ScrollPositionChanged {
23315        local: bool,
23316        autoscroll: bool,
23317    },
23318    TransactionUndone {
23319        transaction_id: clock::Lamport,
23320    },
23321    TransactionBegun {
23322        transaction_id: clock::Lamport,
23323    },
23324    CursorShapeChanged,
23325    BreadcrumbsChanged,
23326    PushedToNavHistory {
23327        anchor: Anchor,
23328        is_deactivate: bool,
23329    },
23330}
23331
23332impl EventEmitter<EditorEvent> for Editor {}
23333
23334impl Focusable for Editor {
23335    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23336        self.focus_handle.clone()
23337    }
23338}
23339
23340impl Render for Editor {
23341    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23342        let settings = ThemeSettings::get_global(cx);
23343
23344        let mut text_style = match self.mode {
23345            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23346                color: cx.theme().colors().editor_foreground,
23347                font_family: settings.ui_font.family.clone(),
23348                font_features: settings.ui_font.features.clone(),
23349                font_fallbacks: settings.ui_font.fallbacks.clone(),
23350                font_size: rems(0.875).into(),
23351                font_weight: settings.ui_font.weight,
23352                line_height: relative(settings.buffer_line_height.value()),
23353                ..Default::default()
23354            },
23355            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23356                color: cx.theme().colors().editor_foreground,
23357                font_family: settings.buffer_font.family.clone(),
23358                font_features: settings.buffer_font.features.clone(),
23359                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23360                font_size: settings.buffer_font_size(cx).into(),
23361                font_weight: settings.buffer_font.weight,
23362                line_height: relative(settings.buffer_line_height.value()),
23363                ..Default::default()
23364            },
23365        };
23366        if let Some(text_style_refinement) = &self.text_style_refinement {
23367            text_style.refine(text_style_refinement)
23368        }
23369
23370        let background = match self.mode {
23371            EditorMode::SingleLine => cx.theme().system().transparent,
23372            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23373            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23374            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23375        };
23376
23377        EditorElement::new(
23378            &cx.entity(),
23379            EditorStyle {
23380                background,
23381                border: cx.theme().colors().border,
23382                local_player: cx.theme().players().local(),
23383                text: text_style,
23384                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23385                syntax: cx.theme().syntax().clone(),
23386                status: cx.theme().status().clone(),
23387                inlay_hints_style: make_inlay_hints_style(cx),
23388                edit_prediction_styles: make_suggestion_styles(cx),
23389                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23390                show_underlines: self.diagnostics_enabled(),
23391            },
23392        )
23393    }
23394}
23395
23396impl EntityInputHandler for Editor {
23397    fn text_for_range(
23398        &mut self,
23399        range_utf16: Range<usize>,
23400        adjusted_range: &mut Option<Range<usize>>,
23401        _: &mut Window,
23402        cx: &mut Context<Self>,
23403    ) -> Option<String> {
23404        let snapshot = self.buffer.read(cx).read(cx);
23405        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23406        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23407        if (start.0..end.0) != range_utf16 {
23408            adjusted_range.replace(start.0..end.0);
23409        }
23410        Some(snapshot.text_for_range(start..end).collect())
23411    }
23412
23413    fn selected_text_range(
23414        &mut self,
23415        ignore_disabled_input: bool,
23416        _: &mut Window,
23417        cx: &mut Context<Self>,
23418    ) -> Option<UTF16Selection> {
23419        // Prevent the IME menu from appearing when holding down an alphabetic key
23420        // while input is disabled.
23421        if !ignore_disabled_input && !self.input_enabled {
23422            return None;
23423        }
23424
23425        let selection = self.selections.newest::<OffsetUtf16>(cx);
23426        let range = selection.range();
23427
23428        Some(UTF16Selection {
23429            range: range.start.0..range.end.0,
23430            reversed: selection.reversed,
23431        })
23432    }
23433
23434    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23435        let snapshot = self.buffer.read(cx).read(cx);
23436        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23437        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23438    }
23439
23440    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23441        self.clear_highlights::<InputComposition>(cx);
23442        self.ime_transaction.take();
23443    }
23444
23445    fn replace_text_in_range(
23446        &mut self,
23447        range_utf16: Option<Range<usize>>,
23448        text: &str,
23449        window: &mut Window,
23450        cx: &mut Context<Self>,
23451    ) {
23452        if !self.input_enabled {
23453            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23454            return;
23455        }
23456
23457        self.transact(window, cx, |this, window, cx| {
23458            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23459                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23460                Some(this.selection_replacement_ranges(range_utf16, cx))
23461            } else {
23462                this.marked_text_ranges(cx)
23463            };
23464
23465            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23466                let newest_selection_id = this.selections.newest_anchor().id;
23467                this.selections
23468                    .all::<OffsetUtf16>(cx)
23469                    .iter()
23470                    .zip(ranges_to_replace.iter())
23471                    .find_map(|(selection, range)| {
23472                        if selection.id == newest_selection_id {
23473                            Some(
23474                                (range.start.0 as isize - selection.head().0 as isize)
23475                                    ..(range.end.0 as isize - selection.head().0 as isize),
23476                            )
23477                        } else {
23478                            None
23479                        }
23480                    })
23481            });
23482
23483            cx.emit(EditorEvent::InputHandled {
23484                utf16_range_to_replace: range_to_replace,
23485                text: text.into(),
23486            });
23487
23488            if let Some(new_selected_ranges) = new_selected_ranges {
23489                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23490                    selections.select_ranges(new_selected_ranges)
23491                });
23492                this.backspace(&Default::default(), window, cx);
23493            }
23494
23495            this.handle_input(text, window, cx);
23496        });
23497
23498        if let Some(transaction) = self.ime_transaction {
23499            self.buffer.update(cx, |buffer, cx| {
23500                buffer.group_until_transaction(transaction, cx);
23501            });
23502        }
23503
23504        self.unmark_text(window, cx);
23505    }
23506
23507    fn replace_and_mark_text_in_range(
23508        &mut self,
23509        range_utf16: Option<Range<usize>>,
23510        text: &str,
23511        new_selected_range_utf16: Option<Range<usize>>,
23512        window: &mut Window,
23513        cx: &mut Context<Self>,
23514    ) {
23515        if !self.input_enabled {
23516            return;
23517        }
23518
23519        let transaction = self.transact(window, cx, |this, window, cx| {
23520            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23521                let snapshot = this.buffer.read(cx).read(cx);
23522                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23523                    for marked_range in &mut marked_ranges {
23524                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23525                        marked_range.start.0 += relative_range_utf16.start;
23526                        marked_range.start =
23527                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23528                        marked_range.end =
23529                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23530                    }
23531                }
23532                Some(marked_ranges)
23533            } else if let Some(range_utf16) = range_utf16 {
23534                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23535                Some(this.selection_replacement_ranges(range_utf16, cx))
23536            } else {
23537                None
23538            };
23539
23540            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23541                let newest_selection_id = this.selections.newest_anchor().id;
23542                this.selections
23543                    .all::<OffsetUtf16>(cx)
23544                    .iter()
23545                    .zip(ranges_to_replace.iter())
23546                    .find_map(|(selection, range)| {
23547                        if selection.id == newest_selection_id {
23548                            Some(
23549                                (range.start.0 as isize - selection.head().0 as isize)
23550                                    ..(range.end.0 as isize - selection.head().0 as isize),
23551                            )
23552                        } else {
23553                            None
23554                        }
23555                    })
23556            });
23557
23558            cx.emit(EditorEvent::InputHandled {
23559                utf16_range_to_replace: range_to_replace,
23560                text: text.into(),
23561            });
23562
23563            if let Some(ranges) = ranges_to_replace {
23564                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23565                    s.select_ranges(ranges)
23566                });
23567            }
23568
23569            let marked_ranges = {
23570                let snapshot = this.buffer.read(cx).read(cx);
23571                this.selections
23572                    .disjoint_anchors()
23573                    .iter()
23574                    .map(|selection| {
23575                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23576                    })
23577                    .collect::<Vec<_>>()
23578            };
23579
23580            if text.is_empty() {
23581                this.unmark_text(window, cx);
23582            } else {
23583                this.highlight_text::<InputComposition>(
23584                    marked_ranges.clone(),
23585                    HighlightStyle {
23586                        underline: Some(UnderlineStyle {
23587                            thickness: px(1.),
23588                            color: None,
23589                            wavy: false,
23590                        }),
23591                        ..Default::default()
23592                    },
23593                    cx,
23594                );
23595            }
23596
23597            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23598            let use_autoclose = this.use_autoclose;
23599            let use_auto_surround = this.use_auto_surround;
23600            this.set_use_autoclose(false);
23601            this.set_use_auto_surround(false);
23602            this.handle_input(text, window, cx);
23603            this.set_use_autoclose(use_autoclose);
23604            this.set_use_auto_surround(use_auto_surround);
23605
23606            if let Some(new_selected_range) = new_selected_range_utf16 {
23607                let snapshot = this.buffer.read(cx).read(cx);
23608                let new_selected_ranges = marked_ranges
23609                    .into_iter()
23610                    .map(|marked_range| {
23611                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23612                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23613                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23614                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23615                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23616                    })
23617                    .collect::<Vec<_>>();
23618
23619                drop(snapshot);
23620                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23621                    selections.select_ranges(new_selected_ranges)
23622                });
23623            }
23624        });
23625
23626        self.ime_transaction = self.ime_transaction.or(transaction);
23627        if let Some(transaction) = self.ime_transaction {
23628            self.buffer.update(cx, |buffer, cx| {
23629                buffer.group_until_transaction(transaction, cx);
23630            });
23631        }
23632
23633        if self.text_highlights::<InputComposition>(cx).is_none() {
23634            self.ime_transaction.take();
23635        }
23636    }
23637
23638    fn bounds_for_range(
23639        &mut self,
23640        range_utf16: Range<usize>,
23641        element_bounds: gpui::Bounds<Pixels>,
23642        window: &mut Window,
23643        cx: &mut Context<Self>,
23644    ) -> Option<gpui::Bounds<Pixels>> {
23645        let text_layout_details = self.text_layout_details(window);
23646        let CharacterDimensions {
23647            em_width,
23648            em_advance,
23649            line_height,
23650        } = self.character_dimensions(window);
23651
23652        let snapshot = self.snapshot(window, cx);
23653        let scroll_position = snapshot.scroll_position();
23654        let scroll_left = scroll_position.x * em_advance;
23655
23656        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23657        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23658            + self.gutter_dimensions.full_width();
23659        let y = line_height * (start.row().as_f32() - scroll_position.y);
23660
23661        Some(Bounds {
23662            origin: element_bounds.origin + point(x, y),
23663            size: size(em_width, line_height),
23664        })
23665    }
23666
23667    fn character_index_for_point(
23668        &mut self,
23669        point: gpui::Point<Pixels>,
23670        _window: &mut Window,
23671        _cx: &mut Context<Self>,
23672    ) -> Option<usize> {
23673        let position_map = self.last_position_map.as_ref()?;
23674        if !position_map.text_hitbox.contains(&point) {
23675            return None;
23676        }
23677        let display_point = position_map.point_for_position(point).previous_valid;
23678        let anchor = position_map
23679            .snapshot
23680            .display_point_to_anchor(display_point, Bias::Left);
23681        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23682        Some(utf16_offset.0)
23683    }
23684}
23685
23686trait SelectionExt {
23687    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23688    fn spanned_rows(
23689        &self,
23690        include_end_if_at_line_start: bool,
23691        map: &DisplaySnapshot,
23692    ) -> Range<MultiBufferRow>;
23693}
23694
23695impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23696    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23697        let start = self
23698            .start
23699            .to_point(&map.buffer_snapshot)
23700            .to_display_point(map);
23701        let end = self
23702            .end
23703            .to_point(&map.buffer_snapshot)
23704            .to_display_point(map);
23705        if self.reversed {
23706            end..start
23707        } else {
23708            start..end
23709        }
23710    }
23711
23712    fn spanned_rows(
23713        &self,
23714        include_end_if_at_line_start: bool,
23715        map: &DisplaySnapshot,
23716    ) -> Range<MultiBufferRow> {
23717        let start = self.start.to_point(&map.buffer_snapshot);
23718        let mut end = self.end.to_point(&map.buffer_snapshot);
23719        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23720            end.row -= 1;
23721        }
23722
23723        let buffer_start = map.prev_line_boundary(start).0;
23724        let buffer_end = map.next_line_boundary(end).0;
23725        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23726    }
23727}
23728
23729impl<T: InvalidationRegion> InvalidationStack<T> {
23730    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23731    where
23732        S: Clone + ToOffset,
23733    {
23734        while let Some(region) = self.last() {
23735            let all_selections_inside_invalidation_ranges =
23736                if selections.len() == region.ranges().len() {
23737                    selections
23738                        .iter()
23739                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23740                        .all(|(selection, invalidation_range)| {
23741                            let head = selection.head().to_offset(buffer);
23742                            invalidation_range.start <= head && invalidation_range.end >= head
23743                        })
23744                } else {
23745                    false
23746                };
23747
23748            if all_selections_inside_invalidation_ranges {
23749                break;
23750            } else {
23751                self.pop();
23752            }
23753        }
23754    }
23755}
23756
23757impl<T> Default for InvalidationStack<T> {
23758    fn default() -> Self {
23759        Self(Default::default())
23760    }
23761}
23762
23763impl<T> Deref for InvalidationStack<T> {
23764    type Target = Vec<T>;
23765
23766    fn deref(&self) -> &Self::Target {
23767        &self.0
23768    }
23769}
23770
23771impl<T> DerefMut for InvalidationStack<T> {
23772    fn deref_mut(&mut self) -> &mut Self::Target {
23773        &mut self.0
23774    }
23775}
23776
23777impl InvalidationRegion for SnippetState {
23778    fn ranges(&self) -> &[Range<Anchor>] {
23779        &self.ranges[self.active_index]
23780    }
23781}
23782
23783fn edit_prediction_edit_text(
23784    current_snapshot: &BufferSnapshot,
23785    edits: &[(Range<Anchor>, String)],
23786    edit_preview: &EditPreview,
23787    include_deletions: bool,
23788    cx: &App,
23789) -> HighlightedText {
23790    let edits = edits
23791        .iter()
23792        .map(|(anchor, text)| {
23793            (
23794                anchor.start.text_anchor..anchor.end.text_anchor,
23795                text.clone(),
23796            )
23797        })
23798        .collect::<Vec<_>>();
23799
23800    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23801}
23802
23803fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23804    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23805    // Just show the raw edit text with basic styling
23806    let mut text = String::new();
23807    let mut highlights = Vec::new();
23808
23809    let insertion_highlight_style = HighlightStyle {
23810        color: Some(cx.theme().colors().text),
23811        ..Default::default()
23812    };
23813
23814    for (_, edit_text) in edits {
23815        let start_offset = text.len();
23816        text.push_str(edit_text);
23817        let end_offset = text.len();
23818
23819        if start_offset < end_offset {
23820            highlights.push((start_offset..end_offset, insertion_highlight_style));
23821        }
23822    }
23823
23824    HighlightedText {
23825        text: text.into(),
23826        highlights,
23827    }
23828}
23829
23830pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23831    match severity {
23832        lsp::DiagnosticSeverity::ERROR => colors.error,
23833        lsp::DiagnosticSeverity::WARNING => colors.warning,
23834        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23835        lsp::DiagnosticSeverity::HINT => colors.info,
23836        _ => colors.ignored,
23837    }
23838}
23839
23840pub fn styled_runs_for_code_label<'a>(
23841    label: &'a CodeLabel,
23842    syntax_theme: &'a theme::SyntaxTheme,
23843) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23844    let fade_out = HighlightStyle {
23845        fade_out: Some(0.35),
23846        ..Default::default()
23847    };
23848
23849    let mut prev_end = label.filter_range.end;
23850    label
23851        .runs
23852        .iter()
23853        .enumerate()
23854        .flat_map(move |(ix, (range, highlight_id))| {
23855            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23856                style
23857            } else {
23858                return Default::default();
23859            };
23860            let muted_style = style.highlight(fade_out);
23861
23862            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23863            if range.start >= label.filter_range.end {
23864                if range.start > prev_end {
23865                    runs.push((prev_end..range.start, fade_out));
23866                }
23867                runs.push((range.clone(), muted_style));
23868            } else if range.end <= label.filter_range.end {
23869                runs.push((range.clone(), style));
23870            } else {
23871                runs.push((range.start..label.filter_range.end, style));
23872                runs.push((label.filter_range.end..range.end, muted_style));
23873            }
23874            prev_end = cmp::max(prev_end, range.end);
23875
23876            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23877                runs.push((prev_end..label.text.len(), fade_out));
23878            }
23879
23880            runs
23881        })
23882}
23883
23884pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23885    let mut prev_index = 0;
23886    let mut prev_codepoint: Option<char> = None;
23887    text.char_indices()
23888        .chain([(text.len(), '\0')])
23889        .filter_map(move |(index, codepoint)| {
23890            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23891            let is_boundary = index == text.len()
23892                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23893                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23894            if is_boundary {
23895                let chunk = &text[prev_index..index];
23896                prev_index = index;
23897                Some(chunk)
23898            } else {
23899                None
23900            }
23901        })
23902}
23903
23904pub trait RangeToAnchorExt: Sized {
23905    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23906
23907    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23908        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23909        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23910    }
23911}
23912
23913impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23914    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23915        let start_offset = self.start.to_offset(snapshot);
23916        let end_offset = self.end.to_offset(snapshot);
23917        if start_offset == end_offset {
23918            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23919        } else {
23920            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23921        }
23922    }
23923}
23924
23925pub trait RowExt {
23926    fn as_f32(&self) -> f32;
23927
23928    fn next_row(&self) -> Self;
23929
23930    fn previous_row(&self) -> Self;
23931
23932    fn minus(&self, other: Self) -> u32;
23933}
23934
23935impl RowExt for DisplayRow {
23936    fn as_f32(&self) -> f32 {
23937        self.0 as f32
23938    }
23939
23940    fn next_row(&self) -> Self {
23941        Self(self.0 + 1)
23942    }
23943
23944    fn previous_row(&self) -> Self {
23945        Self(self.0.saturating_sub(1))
23946    }
23947
23948    fn minus(&self, other: Self) -> u32 {
23949        self.0 - other.0
23950    }
23951}
23952
23953impl RowExt for MultiBufferRow {
23954    fn as_f32(&self) -> f32 {
23955        self.0 as f32
23956    }
23957
23958    fn next_row(&self) -> Self {
23959        Self(self.0 + 1)
23960    }
23961
23962    fn previous_row(&self) -> Self {
23963        Self(self.0.saturating_sub(1))
23964    }
23965
23966    fn minus(&self, other: Self) -> u32 {
23967        self.0 - other.0
23968    }
23969}
23970
23971trait RowRangeExt {
23972    type Row;
23973
23974    fn len(&self) -> usize;
23975
23976    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23977}
23978
23979impl RowRangeExt for Range<MultiBufferRow> {
23980    type Row = MultiBufferRow;
23981
23982    fn len(&self) -> usize {
23983        (self.end.0 - self.start.0) as usize
23984    }
23985
23986    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23987        (self.start.0..self.end.0).map(MultiBufferRow)
23988    }
23989}
23990
23991impl RowRangeExt for Range<DisplayRow> {
23992    type Row = DisplayRow;
23993
23994    fn len(&self) -> usize {
23995        (self.end.0 - self.start.0) as usize
23996    }
23997
23998    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23999        (self.start.0..self.end.0).map(DisplayRow)
24000    }
24001}
24002
24003/// If select range has more than one line, we
24004/// just point the cursor to range.start.
24005fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24006    if range.start.row == range.end.row {
24007        range
24008    } else {
24009        range.start..range.start
24010    }
24011}
24012pub struct KillRing(ClipboardItem);
24013impl Global for KillRing {}
24014
24015const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24016
24017enum BreakpointPromptEditAction {
24018    Log,
24019    Condition,
24020    HitCondition,
24021}
24022
24023struct BreakpointPromptEditor {
24024    pub(crate) prompt: Entity<Editor>,
24025    editor: WeakEntity<Editor>,
24026    breakpoint_anchor: Anchor,
24027    breakpoint: Breakpoint,
24028    edit_action: BreakpointPromptEditAction,
24029    block_ids: HashSet<CustomBlockId>,
24030    editor_margins: Arc<Mutex<EditorMargins>>,
24031    _subscriptions: Vec<Subscription>,
24032}
24033
24034impl BreakpointPromptEditor {
24035    const MAX_LINES: u8 = 4;
24036
24037    fn new(
24038        editor: WeakEntity<Editor>,
24039        breakpoint_anchor: Anchor,
24040        breakpoint: Breakpoint,
24041        edit_action: BreakpointPromptEditAction,
24042        window: &mut Window,
24043        cx: &mut Context<Self>,
24044    ) -> Self {
24045        let base_text = match edit_action {
24046            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24047            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24048            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24049        }
24050        .map(|msg| msg.to_string())
24051        .unwrap_or_default();
24052
24053        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24054        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24055
24056        let prompt = cx.new(|cx| {
24057            let mut prompt = Editor::new(
24058                EditorMode::AutoHeight {
24059                    min_lines: 1,
24060                    max_lines: Some(Self::MAX_LINES as usize),
24061                },
24062                buffer,
24063                None,
24064                window,
24065                cx,
24066            );
24067            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24068            prompt.set_show_cursor_when_unfocused(false, cx);
24069            prompt.set_placeholder_text(
24070                match edit_action {
24071                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24072                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24073                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24074                },
24075                window,
24076                cx,
24077            );
24078
24079            prompt
24080        });
24081
24082        Self {
24083            prompt,
24084            editor,
24085            breakpoint_anchor,
24086            breakpoint,
24087            edit_action,
24088            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24089            block_ids: Default::default(),
24090            _subscriptions: vec![],
24091        }
24092    }
24093
24094    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24095        self.block_ids.extend(block_ids)
24096    }
24097
24098    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24099        if let Some(editor) = self.editor.upgrade() {
24100            let message = self
24101                .prompt
24102                .read(cx)
24103                .buffer
24104                .read(cx)
24105                .as_singleton()
24106                .expect("A multi buffer in breakpoint prompt isn't possible")
24107                .read(cx)
24108                .as_rope()
24109                .to_string();
24110
24111            editor.update(cx, |editor, cx| {
24112                editor.edit_breakpoint_at_anchor(
24113                    self.breakpoint_anchor,
24114                    self.breakpoint.clone(),
24115                    match self.edit_action {
24116                        BreakpointPromptEditAction::Log => {
24117                            BreakpointEditAction::EditLogMessage(message.into())
24118                        }
24119                        BreakpointPromptEditAction::Condition => {
24120                            BreakpointEditAction::EditCondition(message.into())
24121                        }
24122                        BreakpointPromptEditAction::HitCondition => {
24123                            BreakpointEditAction::EditHitCondition(message.into())
24124                        }
24125                    },
24126                    cx,
24127                );
24128
24129                editor.remove_blocks(self.block_ids.clone(), None, cx);
24130                cx.focus_self(window);
24131            });
24132        }
24133    }
24134
24135    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24136        self.editor
24137            .update(cx, |editor, cx| {
24138                editor.remove_blocks(self.block_ids.clone(), None, cx);
24139                window.focus(&editor.focus_handle);
24140            })
24141            .log_err();
24142    }
24143
24144    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24145        let settings = ThemeSettings::get_global(cx);
24146        let text_style = TextStyle {
24147            color: if self.prompt.read(cx).read_only(cx) {
24148                cx.theme().colors().text_disabled
24149            } else {
24150                cx.theme().colors().text
24151            },
24152            font_family: settings.buffer_font.family.clone(),
24153            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24154            font_size: settings.buffer_font_size(cx).into(),
24155            font_weight: settings.buffer_font.weight,
24156            line_height: relative(settings.buffer_line_height.value()),
24157            ..Default::default()
24158        };
24159        EditorElement::new(
24160            &self.prompt,
24161            EditorStyle {
24162                background: cx.theme().colors().editor_background,
24163                local_player: cx.theme().players().local(),
24164                text: text_style,
24165                ..Default::default()
24166            },
24167        )
24168    }
24169}
24170
24171impl Render for BreakpointPromptEditor {
24172    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24173        let editor_margins = *self.editor_margins.lock();
24174        let gutter_dimensions = editor_margins.gutter;
24175        h_flex()
24176            .key_context("Editor")
24177            .bg(cx.theme().colors().editor_background)
24178            .border_y_1()
24179            .border_color(cx.theme().status().info_border)
24180            .size_full()
24181            .py(window.line_height() / 2.5)
24182            .on_action(cx.listener(Self::confirm))
24183            .on_action(cx.listener(Self::cancel))
24184            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24185            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24186    }
24187}
24188
24189impl Focusable for BreakpointPromptEditor {
24190    fn focus_handle(&self, cx: &App) -> FocusHandle {
24191        self.prompt.focus_handle(cx)
24192    }
24193}
24194
24195fn all_edits_insertions_or_deletions(
24196    edits: &Vec<(Range<Anchor>, String)>,
24197    snapshot: &MultiBufferSnapshot,
24198) -> bool {
24199    let mut all_insertions = true;
24200    let mut all_deletions = true;
24201
24202    for (range, new_text) in edits.iter() {
24203        let range_is_empty = range.to_offset(snapshot).is_empty();
24204        let text_is_empty = new_text.is_empty();
24205
24206        if range_is_empty != text_is_empty {
24207            if range_is_empty {
24208                all_deletions = false;
24209            } else {
24210                all_insertions = false;
24211            }
24212        } else {
24213            return false;
24214        }
24215
24216        if !all_insertions && !all_deletions {
24217            return false;
24218        }
24219    }
24220    all_insertions || all_deletions
24221}
24222
24223struct MissingEditPredictionKeybindingTooltip;
24224
24225impl Render for MissingEditPredictionKeybindingTooltip {
24226    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24227        ui::tooltip_container(window, cx, |container, _, cx| {
24228            container
24229                .flex_shrink_0()
24230                .max_w_80()
24231                .min_h(rems_from_px(124.))
24232                .justify_between()
24233                .child(
24234                    v_flex()
24235                        .flex_1()
24236                        .text_ui_sm(cx)
24237                        .child(Label::new("Conflict with Accept Keybinding"))
24238                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24239                )
24240                .child(
24241                    h_flex()
24242                        .pb_1()
24243                        .gap_1()
24244                        .items_end()
24245                        .w_full()
24246                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24247                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24248                        }))
24249                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24250                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24251                        })),
24252                )
24253        })
24254    }
24255}
24256
24257#[derive(Debug, Clone, Copy, PartialEq)]
24258pub struct LineHighlight {
24259    pub background: Background,
24260    pub border: Option<gpui::Hsla>,
24261    pub include_gutter: bool,
24262    pub type_id: Option<TypeId>,
24263}
24264
24265struct LineManipulationResult {
24266    pub new_text: String,
24267    pub line_count_before: usize,
24268    pub line_count_after: usize,
24269}
24270
24271fn render_diff_hunk_controls(
24272    row: u32,
24273    status: &DiffHunkStatus,
24274    hunk_range: Range<Anchor>,
24275    is_created_file: bool,
24276    line_height: Pixels,
24277    editor: &Entity<Editor>,
24278    _window: &mut Window,
24279    cx: &mut App,
24280) -> AnyElement {
24281    h_flex()
24282        .h(line_height)
24283        .mr_1()
24284        .gap_1()
24285        .px_0p5()
24286        .pb_1()
24287        .border_x_1()
24288        .border_b_1()
24289        .border_color(cx.theme().colors().border_variant)
24290        .rounded_b_lg()
24291        .bg(cx.theme().colors().editor_background)
24292        .gap_1()
24293        .block_mouse_except_scroll()
24294        .shadow_md()
24295        .child(if status.has_secondary_hunk() {
24296            Button::new(("stage", row as u64), "Stage")
24297                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24298                .tooltip({
24299                    let focus_handle = editor.focus_handle(cx);
24300                    move |window, cx| {
24301                        Tooltip::for_action_in(
24302                            "Stage Hunk",
24303                            &::git::ToggleStaged,
24304                            &focus_handle,
24305                            window,
24306                            cx,
24307                        )
24308                    }
24309                })
24310                .on_click({
24311                    let editor = editor.clone();
24312                    move |_event, _window, cx| {
24313                        editor.update(cx, |editor, cx| {
24314                            editor.stage_or_unstage_diff_hunks(
24315                                true,
24316                                vec![hunk_range.start..hunk_range.start],
24317                                cx,
24318                            );
24319                        });
24320                    }
24321                })
24322        } else {
24323            Button::new(("unstage", row as u64), "Unstage")
24324                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24325                .tooltip({
24326                    let focus_handle = editor.focus_handle(cx);
24327                    move |window, cx| {
24328                        Tooltip::for_action_in(
24329                            "Unstage Hunk",
24330                            &::git::ToggleStaged,
24331                            &focus_handle,
24332                            window,
24333                            cx,
24334                        )
24335                    }
24336                })
24337                .on_click({
24338                    let editor = editor.clone();
24339                    move |_event, _window, cx| {
24340                        editor.update(cx, |editor, cx| {
24341                            editor.stage_or_unstage_diff_hunks(
24342                                false,
24343                                vec![hunk_range.start..hunk_range.start],
24344                                cx,
24345                            );
24346                        });
24347                    }
24348                })
24349        })
24350        .child(
24351            Button::new(("restore", row as u64), "Restore")
24352                .tooltip({
24353                    let focus_handle = editor.focus_handle(cx);
24354                    move |window, cx| {
24355                        Tooltip::for_action_in(
24356                            "Restore Hunk",
24357                            &::git::Restore,
24358                            &focus_handle,
24359                            window,
24360                            cx,
24361                        )
24362                    }
24363                })
24364                .on_click({
24365                    let editor = editor.clone();
24366                    move |_event, window, cx| {
24367                        editor.update(cx, |editor, cx| {
24368                            let snapshot = editor.snapshot(window, cx);
24369                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24370                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24371                        });
24372                    }
24373                })
24374                .disabled(is_created_file),
24375        )
24376        .when(
24377            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24378            |el| {
24379                el.child(
24380                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24381                        .shape(IconButtonShape::Square)
24382                        .icon_size(IconSize::Small)
24383                        // .disabled(!has_multiple_hunks)
24384                        .tooltip({
24385                            let focus_handle = editor.focus_handle(cx);
24386                            move |window, cx| {
24387                                Tooltip::for_action_in(
24388                                    "Next Hunk",
24389                                    &GoToHunk,
24390                                    &focus_handle,
24391                                    window,
24392                                    cx,
24393                                )
24394                            }
24395                        })
24396                        .on_click({
24397                            let editor = editor.clone();
24398                            move |_event, window, cx| {
24399                                editor.update(cx, |editor, cx| {
24400                                    let snapshot = editor.snapshot(window, cx);
24401                                    let position =
24402                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24403                                    editor.go_to_hunk_before_or_after_position(
24404                                        &snapshot,
24405                                        position,
24406                                        Direction::Next,
24407                                        window,
24408                                        cx,
24409                                    );
24410                                    editor.expand_selected_diff_hunks(cx);
24411                                });
24412                            }
24413                        }),
24414                )
24415                .child(
24416                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24417                        .shape(IconButtonShape::Square)
24418                        .icon_size(IconSize::Small)
24419                        // .disabled(!has_multiple_hunks)
24420                        .tooltip({
24421                            let focus_handle = editor.focus_handle(cx);
24422                            move |window, cx| {
24423                                Tooltip::for_action_in(
24424                                    "Previous Hunk",
24425                                    &GoToPreviousHunk,
24426                                    &focus_handle,
24427                                    window,
24428                                    cx,
24429                                )
24430                            }
24431                        })
24432                        .on_click({
24433                            let editor = editor.clone();
24434                            move |_event, window, cx| {
24435                                editor.update(cx, |editor, cx| {
24436                                    let snapshot = editor.snapshot(window, cx);
24437                                    let point =
24438                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24439                                    editor.go_to_hunk_before_or_after_position(
24440                                        &snapshot,
24441                                        point,
24442                                        Direction::Prev,
24443                                        window,
24444                                        cx,
24445                                    );
24446                                    editor.expand_selected_diff_hunks(cx);
24447                                });
24448                            }
24449                        }),
24450                )
24451            },
24452        )
24453        .into_any_element()
24454}
24455
24456pub fn multibuffer_context_lines(cx: &App) -> u32 {
24457    EditorSettings::try_get(cx)
24458        .map(|settings| settings.excerpt_context_lines)
24459        .unwrap_or(2)
24460        .min(32)
24461}