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, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, 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::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::seq::SliceRandom;
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::{Any, TypeId},
  179    borrow::Cow,
  180    cell::{OnceCell, RefCell},
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  193use theme::{
  194    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  216};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  236
  237pub type RenderDiffHunkControlsFn = Arc<
  238    dyn Fn(
  239        u32,
  240        &DiffHunkStatus,
  241        Range<Anchor>,
  242        bool,
  243        Pixels,
  244        &Entity<Editor>,
  245        &mut Window,
  246        &mut App,
  247    ) -> AnyElement,
  248>;
  249
  250enum ReportEditorEvent {
  251    Saved { auto_saved: bool },
  252    EditorOpened,
  253    Closed,
  254}
  255
  256impl ReportEditorEvent {
  257    pub fn event_type(&self) -> &'static str {
  258        match self {
  259            Self::Saved { .. } => "Editor Saved",
  260            Self::EditorOpened => "Editor Opened",
  261            Self::Closed => "Editor Closed",
  262        }
  263    }
  264}
  265
  266struct InlineValueCache {
  267    enabled: bool,
  268    inlays: Vec<InlayId>,
  269    refresh_task: Task<Option<()>>,
  270}
  271
  272impl InlineValueCache {
  273    fn new(enabled: bool) -> Self {
  274        Self {
  275            enabled,
  276            inlays: Vec::new(),
  277            refresh_task: Task::ready(None),
  278        }
  279    }
  280}
  281
  282#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  283pub enum InlayId {
  284    EditPrediction(usize),
  285    DebuggerValue(usize),
  286    // LSP
  287    Hint(usize),
  288    Color(usize),
  289}
  290
  291impl InlayId {
  292    fn id(&self) -> usize {
  293        match self {
  294            Self::EditPrediction(id) => *id,
  295            Self::DebuggerValue(id) => *id,
  296            Self::Hint(id) => *id,
  297            Self::Color(id) => *id,
  298        }
  299    }
  300}
  301
  302pub enum ActiveDebugLine {}
  303pub enum DebugStackFrameLine {}
  304enum DocumentHighlightRead {}
  305enum DocumentHighlightWrite {}
  306enum InputComposition {}
  307pub enum PendingInput {}
  308enum SelectedTextHighlight {}
  309
  310pub enum ConflictsOuter {}
  311pub enum ConflictsOurs {}
  312pub enum ConflictsTheirs {}
  313pub enum ConflictsOursMarker {}
  314pub enum ConflictsTheirsMarker {}
  315
  316#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  317pub enum Navigated {
  318    Yes,
  319    No,
  320}
  321
  322impl Navigated {
  323    pub fn from_bool(yes: bool) -> Navigated {
  324        if yes { Navigated::Yes } else { Navigated::No }
  325    }
  326}
  327
  328#[derive(Debug, Clone, PartialEq, Eq)]
  329enum DisplayDiffHunk {
  330    Folded {
  331        display_row: DisplayRow,
  332    },
  333    Unfolded {
  334        is_created_file: bool,
  335        diff_base_byte_range: Range<usize>,
  336        display_row_range: Range<DisplayRow>,
  337        multi_buffer_range: Range<Anchor>,
  338        status: DiffHunkStatus,
  339    },
  340}
  341
  342pub enum HideMouseCursorOrigin {
  343    TypingAction,
  344    MovementAction,
  345}
  346
  347pub fn init_settings(cx: &mut App) {
  348    EditorSettings::register(cx);
  349}
  350
  351pub fn init(cx: &mut App) {
  352    init_settings(cx);
  353
  354    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  355
  356    workspace::register_project_item::<Editor>(cx);
  357    workspace::FollowableViewRegistry::register::<Editor>(cx);
  358    workspace::register_serializable_item::<Editor>(cx);
  359
  360    cx.observe_new(
  361        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  362            workspace.register_action(Editor::new_file);
  363            workspace.register_action(Editor::new_file_vertical);
  364            workspace.register_action(Editor::new_file_horizontal);
  365            workspace.register_action(Editor::cancel_language_server_work);
  366            workspace.register_action(Editor::toggle_focus);
  367        },
  368    )
  369    .detach();
  370
  371    cx.on_action(move |_: &workspace::NewFile, cx| {
  372        let app_state = workspace::AppState::global(cx);
  373        if let Some(app_state) = app_state.upgrade() {
  374            workspace::open_new(
  375                Default::default(),
  376                app_state,
  377                cx,
  378                |workspace, window, cx| {
  379                    Editor::new_file(workspace, &Default::default(), window, cx)
  380                },
  381            )
  382            .detach();
  383        }
  384    });
  385    cx.on_action(move |_: &workspace::NewWindow, cx| {
  386        let app_state = workspace::AppState::global(cx);
  387        if let Some(app_state) = app_state.upgrade() {
  388            workspace::open_new(
  389                Default::default(),
  390                app_state,
  391                cx,
  392                |workspace, window, cx| {
  393                    cx.activate(true);
  394                    Editor::new_file(workspace, &Default::default(), window, cx)
  395                },
  396            )
  397            .detach();
  398        }
  399    });
  400}
  401
  402pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  403    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  404}
  405
  406pub trait DiagnosticRenderer {
  407    fn render_group(
  408        &self,
  409        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  410        buffer_id: BufferId,
  411        snapshot: EditorSnapshot,
  412        editor: WeakEntity<Editor>,
  413        cx: &mut App,
  414    ) -> Vec<BlockProperties<Anchor>>;
  415
  416    fn render_hover(
  417        &self,
  418        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  419        range: Range<Point>,
  420        buffer_id: BufferId,
  421        cx: &mut App,
  422    ) -> Option<Entity<markdown::Markdown>>;
  423
  424    fn open_link(
  425        &self,
  426        editor: &mut Editor,
  427        link: SharedString,
  428        window: &mut Window,
  429        cx: &mut Context<Editor>,
  430    );
  431}
  432
  433pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  434
  435impl GlobalDiagnosticRenderer {
  436    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  437        cx.try_global::<Self>().map(|g| g.0.clone())
  438    }
  439}
  440
  441impl gpui::Global for GlobalDiagnosticRenderer {}
  442pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  443    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  444}
  445
  446pub struct SearchWithinRange;
  447
  448trait InvalidationRegion {
  449    fn ranges(&self) -> &[Range<Anchor>];
  450}
  451
  452#[derive(Clone, Debug, PartialEq)]
  453pub enum SelectPhase {
  454    Begin {
  455        position: DisplayPoint,
  456        add: bool,
  457        click_count: usize,
  458    },
  459    BeginColumnar {
  460        position: DisplayPoint,
  461        reset: bool,
  462        mode: ColumnarMode,
  463        goal_column: u32,
  464    },
  465    Extend {
  466        position: DisplayPoint,
  467        click_count: usize,
  468    },
  469    Update {
  470        position: DisplayPoint,
  471        goal_column: u32,
  472        scroll_delta: gpui::Point<f32>,
  473    },
  474    End,
  475}
  476
  477#[derive(Clone, Debug, PartialEq)]
  478pub enum ColumnarMode {
  479    FromMouse,
  480    FromSelection,
  481}
  482
  483#[derive(Clone, Debug)]
  484pub enum SelectMode {
  485    Character,
  486    Word(Range<Anchor>),
  487    Line(Range<Anchor>),
  488    All,
  489}
  490
  491#[derive(Clone, PartialEq, Eq, Debug)]
  492pub enum EditorMode {
  493    SingleLine,
  494    AutoHeight {
  495        min_lines: usize,
  496        max_lines: Option<usize>,
  497    },
  498    Full {
  499        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  500        scale_ui_elements_with_buffer_font_size: bool,
  501        /// When set to `true`, the editor will render a background for the active line.
  502        show_active_line_background: bool,
  503        /// When set to `true`, the editor's height will be determined by its content.
  504        sized_by_content: bool,
  505    },
  506    Minimap {
  507        parent: WeakEntity<Editor>,
  508    },
  509}
  510
  511impl EditorMode {
  512    pub fn full() -> Self {
  513        Self::Full {
  514            scale_ui_elements_with_buffer_font_size: true,
  515            show_active_line_background: true,
  516            sized_by_content: false,
  517        }
  518    }
  519
  520    #[inline]
  521    pub fn is_full(&self) -> bool {
  522        matches!(self, Self::Full { .. })
  523    }
  524
  525    #[inline]
  526    pub fn is_single_line(&self) -> bool {
  527        matches!(self, Self::SingleLine { .. })
  528    }
  529
  530    #[inline]
  531    fn is_minimap(&self) -> bool {
  532        matches!(self, Self::Minimap { .. })
  533    }
  534}
  535
  536#[derive(Copy, Clone, Debug)]
  537pub enum SoftWrap {
  538    /// Prefer not to wrap at all.
  539    ///
  540    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  541    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  542    GitDiff,
  543    /// Prefer a single line generally, unless an overly long line is encountered.
  544    None,
  545    /// Soft wrap lines that exceed the editor width.
  546    EditorWidth,
  547    /// Soft wrap lines at the preferred line length.
  548    Column(u32),
  549    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  550    Bounded(u32),
  551}
  552
  553#[derive(Clone)]
  554pub struct EditorStyle {
  555    pub background: Hsla,
  556    pub border: Hsla,
  557    pub local_player: PlayerColor,
  558    pub text: TextStyle,
  559    pub scrollbar_width: Pixels,
  560    pub syntax: Arc<SyntaxTheme>,
  561    pub status: StatusColors,
  562    pub inlay_hints_style: HighlightStyle,
  563    pub edit_prediction_styles: EditPredictionStyles,
  564    pub unnecessary_code_fade: f32,
  565    pub show_underlines: bool,
  566}
  567
  568impl Default for EditorStyle {
  569    fn default() -> Self {
  570        Self {
  571            background: Hsla::default(),
  572            border: Hsla::default(),
  573            local_player: PlayerColor::default(),
  574            text: TextStyle::default(),
  575            scrollbar_width: Pixels::default(),
  576            syntax: Default::default(),
  577            // HACK: Status colors don't have a real default.
  578            // We should look into removing the status colors from the editor
  579            // style and retrieve them directly from the theme.
  580            status: StatusColors::dark(),
  581            inlay_hints_style: HighlightStyle::default(),
  582            edit_prediction_styles: EditPredictionStyles {
  583                insertion: HighlightStyle::default(),
  584                whitespace: HighlightStyle::default(),
  585            },
  586            unnecessary_code_fade: Default::default(),
  587            show_underlines: true,
  588        }
  589    }
  590}
  591
  592pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  593    let show_background = language_settings::language_settings(None, None, cx)
  594        .inlay_hints
  595        .show_background;
  596
  597    HighlightStyle {
  598        color: Some(cx.theme().status().hint),
  599        background_color: show_background.then(|| cx.theme().status().hint_background),
  600        ..HighlightStyle::default()
  601    }
  602}
  603
  604pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  605    EditPredictionStyles {
  606        insertion: HighlightStyle {
  607            color: Some(cx.theme().status().predictive),
  608            ..HighlightStyle::default()
  609        },
  610        whitespace: HighlightStyle {
  611            background_color: Some(cx.theme().status().created_background),
  612            ..HighlightStyle::default()
  613        },
  614    }
  615}
  616
  617type CompletionId = usize;
  618
  619pub(crate) enum EditDisplayMode {
  620    TabAccept,
  621    DiffPopover,
  622    Inline,
  623}
  624
  625enum EditPrediction {
  626    Edit {
  627        edits: Vec<(Range<Anchor>, String)>,
  628        edit_preview: Option<EditPreview>,
  629        display_mode: EditDisplayMode,
  630        snapshot: BufferSnapshot,
  631    },
  632    Move {
  633        target: Anchor,
  634        snapshot: BufferSnapshot,
  635    },
  636}
  637
  638struct EditPredictionState {
  639    inlay_ids: Vec<InlayId>,
  640    completion: EditPrediction,
  641    completion_id: Option<SharedString>,
  642    invalidation_range: Range<Anchor>,
  643}
  644
  645enum EditPredictionSettings {
  646    Disabled,
  647    Enabled {
  648        show_in_menu: bool,
  649        preview_requires_modifier: bool,
  650    },
  651}
  652
  653enum EditPredictionHighlight {}
  654
  655#[derive(Debug, Clone)]
  656struct InlineDiagnostic {
  657    message: SharedString,
  658    group_id: usize,
  659    is_primary: bool,
  660    start: Point,
  661    severity: lsp::DiagnosticSeverity,
  662}
  663
  664pub enum MenuEditPredictionsPolicy {
  665    Never,
  666    ByProvider,
  667}
  668
  669pub enum EditPredictionPreview {
  670    /// Modifier is not pressed
  671    Inactive { released_too_fast: bool },
  672    /// Modifier pressed
  673    Active {
  674        since: Instant,
  675        previous_scroll_position: Option<ScrollAnchor>,
  676    },
  677}
  678
  679impl EditPredictionPreview {
  680    pub fn released_too_fast(&self) -> bool {
  681        match self {
  682            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  683            EditPredictionPreview::Active { .. } => false,
  684        }
  685    }
  686
  687    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  688        if let EditPredictionPreview::Active {
  689            previous_scroll_position,
  690            ..
  691        } = self
  692        {
  693            *previous_scroll_position = scroll_position;
  694        }
  695    }
  696}
  697
  698pub struct ContextMenuOptions {
  699    pub min_entries_visible: usize,
  700    pub max_entries_visible: usize,
  701    pub placement: Option<ContextMenuPlacement>,
  702}
  703
  704#[derive(Debug, Clone, PartialEq, Eq)]
  705pub enum ContextMenuPlacement {
  706    Above,
  707    Below,
  708}
  709
  710#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  711struct EditorActionId(usize);
  712
  713impl EditorActionId {
  714    pub fn post_inc(&mut self) -> Self {
  715        let answer = self.0;
  716
  717        *self = Self(answer + 1);
  718
  719        Self(answer)
  720    }
  721}
  722
  723// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  724// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  725
  726type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  727type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  728
  729#[derive(Default)]
  730struct ScrollbarMarkerState {
  731    scrollbar_size: Size<Pixels>,
  732    dirty: bool,
  733    markers: Arc<[PaintQuad]>,
  734    pending_refresh: Option<Task<Result<()>>>,
  735}
  736
  737impl ScrollbarMarkerState {
  738    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  739        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  740    }
  741}
  742
  743#[derive(Clone, Copy, PartialEq, Eq)]
  744pub enum MinimapVisibility {
  745    Disabled,
  746    Enabled {
  747        /// The configuration currently present in the users settings.
  748        setting_configuration: bool,
  749        /// Whether to override the currently set visibility from the users setting.
  750        toggle_override: bool,
  751    },
  752}
  753
  754impl MinimapVisibility {
  755    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  756        if mode.is_full() {
  757            Self::Enabled {
  758                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  759                toggle_override: false,
  760            }
  761        } else {
  762            Self::Disabled
  763        }
  764    }
  765
  766    fn hidden(&self) -> Self {
  767        match *self {
  768            Self::Enabled {
  769                setting_configuration,
  770                ..
  771            } => Self::Enabled {
  772                setting_configuration,
  773                toggle_override: setting_configuration,
  774            },
  775            Self::Disabled => Self::Disabled,
  776        }
  777    }
  778
  779    fn disabled(&self) -> bool {
  780        matches!(*self, Self::Disabled)
  781    }
  782
  783    fn settings_visibility(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                ..
  788            } => setting_configuration,
  789            _ => false,
  790        }
  791    }
  792
  793    fn visible(&self) -> bool {
  794        match *self {
  795            Self::Enabled {
  796                setting_configuration,
  797                toggle_override,
  798            } => setting_configuration ^ toggle_override,
  799            _ => false,
  800        }
  801    }
  802
  803    fn toggle_visibility(&self) -> Self {
  804        match *self {
  805            Self::Enabled {
  806                toggle_override,
  807                setting_configuration,
  808            } => Self::Enabled {
  809                setting_configuration,
  810                toggle_override: !toggle_override,
  811            },
  812            Self::Disabled => Self::Disabled,
  813        }
  814    }
  815}
  816
  817#[derive(Clone, Debug)]
  818struct RunnableTasks {
  819    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  820    offset: multi_buffer::Anchor,
  821    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  822    column: u32,
  823    // Values of all named captures, including those starting with '_'
  824    extra_variables: HashMap<String, String>,
  825    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  826    context_range: Range<BufferOffset>,
  827}
  828
  829impl RunnableTasks {
  830    fn resolve<'a>(
  831        &'a self,
  832        cx: &'a task::TaskContext,
  833    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  834        self.templates.iter().filter_map(|(kind, template)| {
  835            template
  836                .resolve_task(&kind.to_id_base(), cx)
  837                .map(|task| (kind.clone(), task))
  838        })
  839    }
  840}
  841
  842#[derive(Clone)]
  843pub struct ResolvedTasks {
  844    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  845    position: Anchor,
  846}
  847
  848#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  849struct BufferOffset(usize);
  850
  851/// Addons allow storing per-editor state in other crates (e.g. Vim)
  852pub trait Addon: 'static {
  853    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  854
  855    fn render_buffer_header_controls(
  856        &self,
  857        _: &ExcerptInfo,
  858        _: &Window,
  859        _: &App,
  860    ) -> Option<AnyElement> {
  861        None
  862    }
  863
  864    fn to_any(&self) -> &dyn std::any::Any;
  865
  866    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  867        None
  868    }
  869}
  870
  871struct ChangeLocation {
  872    current: Option<Vec<Anchor>>,
  873    original: Vec<Anchor>,
  874}
  875impl ChangeLocation {
  876    fn locations(&self) -> &[Anchor] {
  877        self.current.as_ref().unwrap_or(&self.original)
  878    }
  879}
  880
  881/// A set of caret positions, registered when the editor was edited.
  882pub struct ChangeList {
  883    changes: Vec<ChangeLocation>,
  884    /// Currently "selected" change.
  885    position: Option<usize>,
  886}
  887
  888impl ChangeList {
  889    pub fn new() -> Self {
  890        Self {
  891            changes: Vec::new(),
  892            position: None,
  893        }
  894    }
  895
  896    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  897    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  898    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  899        if self.changes.is_empty() {
  900            return None;
  901        }
  902
  903        let prev = self.position.unwrap_or(self.changes.len());
  904        let next = if direction == Direction::Prev {
  905            prev.saturating_sub(count)
  906        } else {
  907            (prev + count).min(self.changes.len() - 1)
  908        };
  909        self.position = Some(next);
  910        self.changes.get(next).map(|change| change.locations())
  911    }
  912
  913    /// Adds a new change to the list, resetting the change list position.
  914    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  915        self.position.take();
  916        if let Some(last) = self.changes.last_mut()
  917            && group
  918        {
  919            last.current = Some(new_positions)
  920        } else {
  921            self.changes.push(ChangeLocation {
  922                original: new_positions,
  923                current: None,
  924            });
  925        }
  926    }
  927
  928    pub fn last(&self) -> Option<&[Anchor]> {
  929        self.changes.last().map(|change| change.locations())
  930    }
  931
  932    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  933        self.changes.last().map(|change| change.original.as_slice())
  934    }
  935
  936    pub fn invert_last_group(&mut self) {
  937        if let Some(last) = self.changes.last_mut()
  938            && let Some(current) = last.current.as_mut()
  939        {
  940            mem::swap(&mut last.original, current);
  941        }
  942    }
  943}
  944
  945#[derive(Clone)]
  946struct InlineBlamePopoverState {
  947    scroll_handle: ScrollHandle,
  948    commit_message: Option<ParsedCommitMessage>,
  949    markdown: Entity<Markdown>,
  950}
  951
  952struct InlineBlamePopover {
  953    position: gpui::Point<Pixels>,
  954    hide_task: Option<Task<()>>,
  955    popover_bounds: Option<Bounds<Pixels>>,
  956    popover_state: InlineBlamePopoverState,
  957    keyboard_grace: bool,
  958}
  959
  960enum SelectionDragState {
  961    /// State when no drag related activity is detected.
  962    None,
  963    /// State when the mouse is down on a selection that is about to be dragged.
  964    ReadyToDrag {
  965        selection: Selection<Anchor>,
  966        click_position: gpui::Point<Pixels>,
  967        mouse_down_time: Instant,
  968    },
  969    /// State when the mouse is dragging the selection in the editor.
  970    Dragging {
  971        selection: Selection<Anchor>,
  972        drop_cursor: Selection<Anchor>,
  973        hide_drop_cursor: bool,
  974    },
  975}
  976
  977enum ColumnarSelectionState {
  978    FromMouse {
  979        selection_tail: Anchor,
  980        display_point: Option<DisplayPoint>,
  981    },
  982    FromSelection {
  983        selection_tail: Anchor,
  984    },
  985}
  986
  987/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  988/// a breakpoint on them.
  989#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  990struct PhantomBreakpointIndicator {
  991    display_row: DisplayRow,
  992    /// There's a small debounce between hovering over the line and showing the indicator.
  993    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  994    is_active: bool,
  995    collides_with_existing_breakpoint: bool,
  996}
  997
  998/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  999///
 1000/// See the [module level documentation](self) for more information.
 1001pub struct Editor {
 1002    focus_handle: FocusHandle,
 1003    last_focused_descendant: Option<WeakFocusHandle>,
 1004    /// The text buffer being edited
 1005    buffer: Entity<MultiBuffer>,
 1006    /// Map of how text in the buffer should be displayed.
 1007    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1008    pub display_map: Entity<DisplayMap>,
 1009    placeholder_display_map: Option<Entity<DisplayMap>>,
 1010    pub selections: SelectionsCollection,
 1011    pub scroll_manager: ScrollManager,
 1012    /// When inline assist editors are linked, they all render cursors because
 1013    /// typing enters text into each of them, even the ones that aren't focused.
 1014    pub(crate) show_cursor_when_unfocused: bool,
 1015    columnar_selection_state: Option<ColumnarSelectionState>,
 1016    add_selections_state: Option<AddSelectionsState>,
 1017    select_next_state: Option<SelectNextState>,
 1018    select_prev_state: Option<SelectNextState>,
 1019    selection_history: SelectionHistory,
 1020    defer_selection_effects: bool,
 1021    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1022    autoclose_regions: Vec<AutocloseRegion>,
 1023    snippet_stack: InvalidationStack<SnippetState>,
 1024    select_syntax_node_history: SelectSyntaxNodeHistory,
 1025    ime_transaction: Option<TransactionId>,
 1026    pub diagnostics_max_severity: DiagnosticSeverity,
 1027    active_diagnostics: ActiveDiagnostic,
 1028    show_inline_diagnostics: bool,
 1029    inline_diagnostics_update: Task<()>,
 1030    inline_diagnostics_enabled: bool,
 1031    diagnostics_enabled: bool,
 1032    word_completions_enabled: bool,
 1033    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1034    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1035    hard_wrap: Option<usize>,
 1036    project: Option<Entity<Project>>,
 1037    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1038    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1039    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1040    blink_manager: Entity<BlinkManager>,
 1041    show_cursor_names: bool,
 1042    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1043    pub show_local_selections: bool,
 1044    mode: EditorMode,
 1045    show_breadcrumbs: bool,
 1046    show_gutter: bool,
 1047    show_scrollbars: ScrollbarAxes,
 1048    minimap_visibility: MinimapVisibility,
 1049    offset_content: bool,
 1050    disable_expand_excerpt_buttons: bool,
 1051    show_line_numbers: Option<bool>,
 1052    use_relative_line_numbers: Option<bool>,
 1053    show_git_diff_gutter: Option<bool>,
 1054    show_code_actions: Option<bool>,
 1055    show_runnables: Option<bool>,
 1056    show_breakpoints: Option<bool>,
 1057    show_wrap_guides: Option<bool>,
 1058    show_indent_guides: Option<bool>,
 1059    highlight_order: usize,
 1060    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1061    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1062    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1063    scrollbar_marker_state: ScrollbarMarkerState,
 1064    active_indent_guides_state: ActiveIndentGuidesState,
 1065    nav_history: Option<ItemNavHistory>,
 1066    context_menu: RefCell<Option<CodeContextMenu>>,
 1067    context_menu_options: Option<ContextMenuOptions>,
 1068    mouse_context_menu: Option<MouseContextMenu>,
 1069    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1070    inline_blame_popover: Option<InlineBlamePopover>,
 1071    inline_blame_popover_show_task: Option<Task<()>>,
 1072    signature_help_state: SignatureHelpState,
 1073    auto_signature_help: Option<bool>,
 1074    find_all_references_task_sources: Vec<Anchor>,
 1075    next_completion_id: CompletionId,
 1076    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1077    code_actions_task: Option<Task<Result<()>>>,
 1078    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1079    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1080    document_highlights_task: Option<Task<()>>,
 1081    linked_editing_range_task: Option<Task<Option<()>>>,
 1082    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1083    pending_rename: Option<RenameState>,
 1084    searchable: bool,
 1085    cursor_shape: CursorShape,
 1086    current_line_highlight: Option<CurrentLineHighlight>,
 1087    collapse_matches: bool,
 1088    autoindent_mode: Option<AutoindentMode>,
 1089    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1090    input_enabled: bool,
 1091    use_modal_editing: bool,
 1092    read_only: bool,
 1093    leader_id: Option<CollaboratorId>,
 1094    remote_id: Option<ViewId>,
 1095    pub hover_state: HoverState,
 1096    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1097    gutter_hovered: bool,
 1098    hovered_link_state: Option<HoveredLinkState>,
 1099    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1100    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1101    active_edit_prediction: Option<EditPredictionState>,
 1102    /// Used to prevent flickering as the user types while the menu is open
 1103    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1104    edit_prediction_settings: EditPredictionSettings,
 1105    edit_predictions_hidden_for_vim_mode: bool,
 1106    show_edit_predictions_override: Option<bool>,
 1107    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1108    edit_prediction_preview: EditPredictionPreview,
 1109    edit_prediction_indent_conflict: bool,
 1110    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1111    inlay_hint_cache: InlayHintCache,
 1112    next_inlay_id: usize,
 1113    _subscriptions: Vec<Subscription>,
 1114    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1115    gutter_dimensions: GutterDimensions,
 1116    style: Option<EditorStyle>,
 1117    text_style_refinement: Option<TextStyleRefinement>,
 1118    next_editor_action_id: EditorActionId,
 1119    editor_actions: Rc<
 1120        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1121    >,
 1122    use_autoclose: bool,
 1123    use_auto_surround: bool,
 1124    auto_replace_emoji_shortcode: bool,
 1125    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1126    show_git_blame_gutter: bool,
 1127    show_git_blame_inline: bool,
 1128    show_git_blame_inline_delay_task: Option<Task<()>>,
 1129    git_blame_inline_enabled: bool,
 1130    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1131    serialize_dirty_buffers: bool,
 1132    show_selection_menu: Option<bool>,
 1133    blame: Option<Entity<GitBlame>>,
 1134    blame_subscription: Option<Subscription>,
 1135    custom_context_menu: Option<
 1136        Box<
 1137            dyn 'static
 1138                + Fn(
 1139                    &mut Self,
 1140                    DisplayPoint,
 1141                    &mut Window,
 1142                    &mut Context<Self>,
 1143                ) -> Option<Entity<ui::ContextMenu>>,
 1144        >,
 1145    >,
 1146    last_bounds: Option<Bounds<Pixels>>,
 1147    last_position_map: Option<Rc<PositionMap>>,
 1148    expect_bounds_change: Option<Bounds<Pixels>>,
 1149    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1150    tasks_update_task: Option<Task<()>>,
 1151    breakpoint_store: Option<Entity<BreakpointStore>>,
 1152    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1153    hovered_diff_hunk_row: Option<DisplayRow>,
 1154    pull_diagnostics_task: Task<()>,
 1155    in_project_search: bool,
 1156    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1157    breadcrumb_header: Option<String>,
 1158    focused_block: Option<FocusedBlock>,
 1159    next_scroll_position: NextScrollCursorCenterTopBottom,
 1160    addons: HashMap<TypeId, Box<dyn Addon>>,
 1161    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1162    load_diff_task: Option<Shared<Task<()>>>,
 1163    /// Whether we are temporarily displaying a diff other than git's
 1164    temporary_diff_override: bool,
 1165    selection_mark_mode: bool,
 1166    toggle_fold_multiple_buffers: Task<()>,
 1167    _scroll_cursor_center_top_bottom_task: Task<()>,
 1168    serialize_selections: Task<()>,
 1169    serialize_folds: Task<()>,
 1170    mouse_cursor_hidden: bool,
 1171    minimap: Option<Entity<Self>>,
 1172    hide_mouse_mode: HideMouseMode,
 1173    pub change_list: ChangeList,
 1174    inline_value_cache: InlineValueCache,
 1175    selection_drag_state: SelectionDragState,
 1176    next_color_inlay_id: usize,
 1177    colors: Option<LspColorData>,
 1178    folding_newlines: Task<()>,
 1179    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1180}
 1181
 1182#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1183enum NextScrollCursorCenterTopBottom {
 1184    #[default]
 1185    Center,
 1186    Top,
 1187    Bottom,
 1188}
 1189
 1190impl NextScrollCursorCenterTopBottom {
 1191    fn next(&self) -> Self {
 1192        match self {
 1193            Self::Center => Self::Top,
 1194            Self::Top => Self::Bottom,
 1195            Self::Bottom => Self::Center,
 1196        }
 1197    }
 1198}
 1199
 1200#[derive(Clone)]
 1201pub struct EditorSnapshot {
 1202    pub mode: EditorMode,
 1203    show_gutter: bool,
 1204    show_line_numbers: Option<bool>,
 1205    show_git_diff_gutter: Option<bool>,
 1206    show_code_actions: Option<bool>,
 1207    show_runnables: Option<bool>,
 1208    show_breakpoints: Option<bool>,
 1209    git_blame_gutter_max_author_length: Option<usize>,
 1210    pub display_snapshot: DisplaySnapshot,
 1211    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1212    is_focused: bool,
 1213    scroll_anchor: ScrollAnchor,
 1214    ongoing_scroll: OngoingScroll,
 1215    current_line_highlight: CurrentLineHighlight,
 1216    gutter_hovered: bool,
 1217}
 1218
 1219#[derive(Default, Debug, Clone, Copy)]
 1220pub struct GutterDimensions {
 1221    pub left_padding: Pixels,
 1222    pub right_padding: Pixels,
 1223    pub width: Pixels,
 1224    pub margin: Pixels,
 1225    pub git_blame_entries_width: Option<Pixels>,
 1226}
 1227
 1228impl GutterDimensions {
 1229    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1230        Self {
 1231            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1232            ..Default::default()
 1233        }
 1234    }
 1235
 1236    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1237        -cx.text_system().descent(font_id, font_size)
 1238    }
 1239    /// The full width of the space taken up by the gutter.
 1240    pub fn full_width(&self) -> Pixels {
 1241        self.margin + self.width
 1242    }
 1243
 1244    /// The width of the space reserved for the fold indicators,
 1245    /// use alongside 'justify_end' and `gutter_width` to
 1246    /// right align content with the line numbers
 1247    pub fn fold_area_width(&self) -> Pixels {
 1248        self.margin + self.right_padding
 1249    }
 1250}
 1251
 1252struct CharacterDimensions {
 1253    em_width: Pixels,
 1254    em_advance: Pixels,
 1255    line_height: Pixels,
 1256}
 1257
 1258#[derive(Debug)]
 1259pub struct RemoteSelection {
 1260    pub replica_id: ReplicaId,
 1261    pub selection: Selection<Anchor>,
 1262    pub cursor_shape: CursorShape,
 1263    pub collaborator_id: CollaboratorId,
 1264    pub line_mode: bool,
 1265    pub user_name: Option<SharedString>,
 1266    pub color: PlayerColor,
 1267}
 1268
 1269#[derive(Clone, Debug)]
 1270struct SelectionHistoryEntry {
 1271    selections: Arc<[Selection<Anchor>]>,
 1272    select_next_state: Option<SelectNextState>,
 1273    select_prev_state: Option<SelectNextState>,
 1274    add_selections_state: Option<AddSelectionsState>,
 1275}
 1276
 1277#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1278enum SelectionHistoryMode {
 1279    Normal,
 1280    Undoing,
 1281    Redoing,
 1282    Skipping,
 1283}
 1284
 1285#[derive(Clone, PartialEq, Eq, Hash)]
 1286struct HoveredCursor {
 1287    replica_id: u16,
 1288    selection_id: usize,
 1289}
 1290
 1291impl Default for SelectionHistoryMode {
 1292    fn default() -> Self {
 1293        Self::Normal
 1294    }
 1295}
 1296
 1297#[derive(Debug)]
 1298/// SelectionEffects controls the side-effects of updating the selection.
 1299///
 1300/// The default behaviour does "what you mostly want":
 1301/// - it pushes to the nav history if the cursor moved by >10 lines
 1302/// - it re-triggers completion requests
 1303/// - it scrolls to fit
 1304///
 1305/// You might want to modify these behaviours. For example when doing a "jump"
 1306/// like go to definition, we always want to add to nav history; but when scrolling
 1307/// in vim mode we never do.
 1308///
 1309/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1310/// move.
 1311#[derive(Clone)]
 1312pub struct SelectionEffects {
 1313    nav_history: Option<bool>,
 1314    completions: bool,
 1315    scroll: Option<Autoscroll>,
 1316}
 1317
 1318impl Default for SelectionEffects {
 1319    fn default() -> Self {
 1320        Self {
 1321            nav_history: None,
 1322            completions: true,
 1323            scroll: Some(Autoscroll::fit()),
 1324        }
 1325    }
 1326}
 1327impl SelectionEffects {
 1328    pub fn scroll(scroll: Autoscroll) -> Self {
 1329        Self {
 1330            scroll: Some(scroll),
 1331            ..Default::default()
 1332        }
 1333    }
 1334
 1335    pub fn no_scroll() -> Self {
 1336        Self {
 1337            scroll: None,
 1338            ..Default::default()
 1339        }
 1340    }
 1341
 1342    pub fn completions(self, completions: bool) -> Self {
 1343        Self {
 1344            completions,
 1345            ..self
 1346        }
 1347    }
 1348
 1349    pub fn nav_history(self, nav_history: bool) -> Self {
 1350        Self {
 1351            nav_history: Some(nav_history),
 1352            ..self
 1353        }
 1354    }
 1355}
 1356
 1357struct DeferredSelectionEffectsState {
 1358    changed: bool,
 1359    effects: SelectionEffects,
 1360    old_cursor_position: Anchor,
 1361    history_entry: SelectionHistoryEntry,
 1362}
 1363
 1364#[derive(Default)]
 1365struct SelectionHistory {
 1366    #[allow(clippy::type_complexity)]
 1367    selections_by_transaction:
 1368        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1369    mode: SelectionHistoryMode,
 1370    undo_stack: VecDeque<SelectionHistoryEntry>,
 1371    redo_stack: VecDeque<SelectionHistoryEntry>,
 1372}
 1373
 1374impl SelectionHistory {
 1375    #[track_caller]
 1376    fn insert_transaction(
 1377        &mut self,
 1378        transaction_id: TransactionId,
 1379        selections: Arc<[Selection<Anchor>]>,
 1380    ) {
 1381        if selections.is_empty() {
 1382            log::error!(
 1383                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1384                std::panic::Location::caller()
 1385            );
 1386            return;
 1387        }
 1388        self.selections_by_transaction
 1389            .insert(transaction_id, (selections, None));
 1390    }
 1391
 1392    #[allow(clippy::type_complexity)]
 1393    fn transaction(
 1394        &self,
 1395        transaction_id: TransactionId,
 1396    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1397        self.selections_by_transaction.get(&transaction_id)
 1398    }
 1399
 1400    #[allow(clippy::type_complexity)]
 1401    fn transaction_mut(
 1402        &mut self,
 1403        transaction_id: TransactionId,
 1404    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1405        self.selections_by_transaction.get_mut(&transaction_id)
 1406    }
 1407
 1408    fn push(&mut self, entry: SelectionHistoryEntry) {
 1409        if !entry.selections.is_empty() {
 1410            match self.mode {
 1411                SelectionHistoryMode::Normal => {
 1412                    self.push_undo(entry);
 1413                    self.redo_stack.clear();
 1414                }
 1415                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1416                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1417                SelectionHistoryMode::Skipping => {}
 1418            }
 1419        }
 1420    }
 1421
 1422    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1423        if self
 1424            .undo_stack
 1425            .back()
 1426            .is_none_or(|e| e.selections != entry.selections)
 1427        {
 1428            self.undo_stack.push_back(entry);
 1429            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1430                self.undo_stack.pop_front();
 1431            }
 1432        }
 1433    }
 1434
 1435    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1436        if self
 1437            .redo_stack
 1438            .back()
 1439            .is_none_or(|e| e.selections != entry.selections)
 1440        {
 1441            self.redo_stack.push_back(entry);
 1442            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1443                self.redo_stack.pop_front();
 1444            }
 1445        }
 1446    }
 1447}
 1448
 1449#[derive(Clone, Copy)]
 1450pub struct RowHighlightOptions {
 1451    pub autoscroll: bool,
 1452    pub include_gutter: bool,
 1453}
 1454
 1455impl Default for RowHighlightOptions {
 1456    fn default() -> Self {
 1457        Self {
 1458            autoscroll: Default::default(),
 1459            include_gutter: true,
 1460        }
 1461    }
 1462}
 1463
 1464struct RowHighlight {
 1465    index: usize,
 1466    range: Range<Anchor>,
 1467    color: Hsla,
 1468    options: RowHighlightOptions,
 1469    type_id: TypeId,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsState {
 1474    groups: Vec<AddSelectionsGroup>,
 1475}
 1476
 1477#[derive(Clone, Debug)]
 1478struct AddSelectionsGroup {
 1479    above: bool,
 1480    stack: Vec<usize>,
 1481}
 1482
 1483#[derive(Clone)]
 1484struct SelectNextState {
 1485    query: AhoCorasick,
 1486    wordwise: bool,
 1487    done: bool,
 1488}
 1489
 1490impl std::fmt::Debug for SelectNextState {
 1491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1492        f.debug_struct(std::any::type_name::<Self>())
 1493            .field("wordwise", &self.wordwise)
 1494            .field("done", &self.done)
 1495            .finish()
 1496    }
 1497}
 1498
 1499#[derive(Debug)]
 1500struct AutocloseRegion {
 1501    selection_id: usize,
 1502    range: Range<Anchor>,
 1503    pair: BracketPair,
 1504}
 1505
 1506#[derive(Debug)]
 1507struct SnippetState {
 1508    ranges: Vec<Vec<Range<Anchor>>>,
 1509    active_index: usize,
 1510    choices: Vec<Option<Vec<String>>>,
 1511}
 1512
 1513#[doc(hidden)]
 1514pub struct RenameState {
 1515    pub range: Range<Anchor>,
 1516    pub old_name: Arc<str>,
 1517    pub editor: Entity<Editor>,
 1518    block_id: CustomBlockId,
 1519}
 1520
 1521struct InvalidationStack<T>(Vec<T>);
 1522
 1523struct RegisteredEditPredictionProvider {
 1524    provider: Arc<dyn EditPredictionProviderHandle>,
 1525    _subscription: Subscription,
 1526}
 1527
 1528#[derive(Debug, PartialEq, Eq)]
 1529pub struct ActiveDiagnosticGroup {
 1530    pub active_range: Range<Anchor>,
 1531    pub active_message: String,
 1532    pub group_id: usize,
 1533    pub blocks: HashSet<CustomBlockId>,
 1534}
 1535
 1536#[derive(Debug, PartialEq, Eq)]
 1537
 1538pub(crate) enum ActiveDiagnostic {
 1539    None,
 1540    All,
 1541    Group(ActiveDiagnosticGroup),
 1542}
 1543
 1544#[derive(Serialize, Deserialize, Clone, Debug)]
 1545pub struct ClipboardSelection {
 1546    /// The number of bytes in this selection.
 1547    pub len: usize,
 1548    /// Whether this was a full-line selection.
 1549    pub is_entire_line: bool,
 1550    /// The indentation of the first line when this content was originally copied.
 1551    pub first_line_indent: u32,
 1552}
 1553
 1554// selections, scroll behavior, was newest selection reversed
 1555type SelectSyntaxNodeHistoryState = (
 1556    Box<[Selection<usize>]>,
 1557    SelectSyntaxNodeScrollBehavior,
 1558    bool,
 1559);
 1560
 1561#[derive(Default)]
 1562struct SelectSyntaxNodeHistory {
 1563    stack: Vec<SelectSyntaxNodeHistoryState>,
 1564    // disable temporarily to allow changing selections without losing the stack
 1565    pub disable_clearing: bool,
 1566}
 1567
 1568impl SelectSyntaxNodeHistory {
 1569    pub fn try_clear(&mut self) {
 1570        if !self.disable_clearing {
 1571            self.stack.clear();
 1572        }
 1573    }
 1574
 1575    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1576        self.stack.push(selection);
 1577    }
 1578
 1579    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1580        self.stack.pop()
 1581    }
 1582}
 1583
 1584enum SelectSyntaxNodeScrollBehavior {
 1585    CursorTop,
 1586    FitSelection,
 1587    CursorBottom,
 1588}
 1589
 1590#[derive(Debug)]
 1591pub(crate) struct NavigationData {
 1592    cursor_anchor: Anchor,
 1593    cursor_position: Point,
 1594    scroll_anchor: ScrollAnchor,
 1595    scroll_top_row: u32,
 1596}
 1597
 1598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1599pub enum GotoDefinitionKind {
 1600    Symbol,
 1601    Declaration,
 1602    Type,
 1603    Implementation,
 1604}
 1605
 1606#[derive(Debug, Clone)]
 1607enum InlayHintRefreshReason {
 1608    ModifiersChanged(bool),
 1609    Toggle(bool),
 1610    SettingsChange(InlayHintSettings),
 1611    NewLinesShown,
 1612    BufferEdited(HashSet<Arc<Language>>),
 1613    RefreshRequested,
 1614    ExcerptsRemoved(Vec<ExcerptId>),
 1615}
 1616
 1617impl InlayHintRefreshReason {
 1618    fn description(&self) -> &'static str {
 1619        match self {
 1620            Self::ModifiersChanged(_) => "modifiers changed",
 1621            Self::Toggle(_) => "toggle",
 1622            Self::SettingsChange(_) => "settings change",
 1623            Self::NewLinesShown => "new lines shown",
 1624            Self::BufferEdited(_) => "buffer edited",
 1625            Self::RefreshRequested => "refresh requested",
 1626            Self::ExcerptsRemoved(_) => "excerpts removed",
 1627        }
 1628    }
 1629}
 1630
 1631pub enum FormatTarget {
 1632    Buffers(HashSet<Entity<Buffer>>),
 1633    Ranges(Vec<Range<MultiBufferPoint>>),
 1634}
 1635
 1636pub(crate) struct FocusedBlock {
 1637    id: BlockId,
 1638    focus_handle: WeakFocusHandle,
 1639}
 1640
 1641#[derive(Clone)]
 1642enum JumpData {
 1643    MultiBufferRow {
 1644        row: MultiBufferRow,
 1645        line_offset_from_top: u32,
 1646    },
 1647    MultiBufferPoint {
 1648        excerpt_id: ExcerptId,
 1649        position: Point,
 1650        anchor: text::Anchor,
 1651        line_offset_from_top: u32,
 1652    },
 1653}
 1654
 1655pub enum MultibufferSelectionMode {
 1656    First,
 1657    All,
 1658}
 1659
 1660#[derive(Clone, Copy, Debug, Default)]
 1661pub struct RewrapOptions {
 1662    pub override_language_settings: bool,
 1663    pub preserve_existing_whitespace: bool,
 1664}
 1665
 1666impl Editor {
 1667    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::full(), buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn auto_height(
 1680        min_lines: usize,
 1681        max_lines: usize,
 1682        window: &mut Window,
 1683        cx: &mut Context<Self>,
 1684    ) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(
 1688            EditorMode::AutoHeight {
 1689                min_lines,
 1690                max_lines: Some(max_lines),
 1691            },
 1692            buffer,
 1693            None,
 1694            window,
 1695            cx,
 1696        )
 1697    }
 1698
 1699    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1700    /// The editor grows as tall as needed to fit its content.
 1701    pub fn auto_height_unbounded(
 1702        min_lines: usize,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        let buffer = cx.new(|cx| Buffer::local("", cx));
 1707        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1708        Self::new(
 1709            EditorMode::AutoHeight {
 1710                min_lines,
 1711                max_lines: None,
 1712            },
 1713            buffer,
 1714            None,
 1715            window,
 1716            cx,
 1717        )
 1718    }
 1719
 1720    pub fn for_buffer(
 1721        buffer: Entity<Buffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(EditorMode::full(), buffer, project, window, cx)
 1728    }
 1729
 1730    pub fn for_multibuffer(
 1731        buffer: Entity<MultiBuffer>,
 1732        project: Option<Entity<Project>>,
 1733        window: &mut Window,
 1734        cx: &mut Context<Self>,
 1735    ) -> Self {
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1740        let mut clone = Self::new(
 1741            self.mode.clone(),
 1742            self.buffer.clone(),
 1743            self.project.clone(),
 1744            window,
 1745            cx,
 1746        );
 1747        self.display_map.update(cx, |display_map, cx| {
 1748            let snapshot = display_map.snapshot(cx);
 1749            clone.display_map.update(cx, |display_map, cx| {
 1750                display_map.set_state(&snapshot, cx);
 1751            });
 1752        });
 1753        clone.folds_did_change(cx);
 1754        clone.selections.clone_state(&self.selections);
 1755        clone.scroll_manager.clone_state(&self.scroll_manager);
 1756        clone.searchable = self.searchable;
 1757        clone.read_only = self.read_only;
 1758        clone
 1759    }
 1760
 1761    pub fn new(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        Editor::new_internal(mode, buffer, project, None, window, cx)
 1769    }
 1770
 1771    fn new_internal(
 1772        mode: EditorMode,
 1773        buffer: Entity<MultiBuffer>,
 1774        project: Option<Entity<Project>>,
 1775        display_map: Option<Entity<DisplayMap>>,
 1776        window: &mut Window,
 1777        cx: &mut Context<Self>,
 1778    ) -> Self {
 1779        debug_assert!(
 1780            display_map.is_none() || mode.is_minimap(),
 1781            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1782        );
 1783
 1784        let full_mode = mode.is_full();
 1785        let is_minimap = mode.is_minimap();
 1786        let diagnostics_max_severity = if full_mode {
 1787            EditorSettings::get_global(cx)
 1788                .diagnostics_max_severity
 1789                .unwrap_or(DiagnosticSeverity::Hint)
 1790        } else {
 1791            DiagnosticSeverity::Off
 1792        };
 1793        let style = window.text_style();
 1794        let font_size = style.font_size.to_pixels(window.rem_size());
 1795        let editor = cx.entity().downgrade();
 1796        let fold_placeholder = FoldPlaceholder {
 1797            constrain_width: false,
 1798            render: Arc::new(move |fold_id, fold_range, cx| {
 1799                let editor = editor.clone();
 1800                div()
 1801                    .id(fold_id)
 1802                    .bg(cx.theme().colors().ghost_element_background)
 1803                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1804                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1805                    .rounded_xs()
 1806                    .size_full()
 1807                    .cursor_pointer()
 1808                    .child("")
 1809                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1810                    .on_click(move |_, _window, cx| {
 1811                        editor
 1812                            .update(cx, |editor, cx| {
 1813                                editor.unfold_ranges(
 1814                                    &[fold_range.start..fold_range.end],
 1815                                    true,
 1816                                    false,
 1817                                    cx,
 1818                                );
 1819                                cx.stop_propagation();
 1820                            })
 1821                            .ok();
 1822                    })
 1823                    .into_any()
 1824            }),
 1825            merge_adjacent: true,
 1826            ..FoldPlaceholder::default()
 1827        };
 1828        let display_map = display_map.unwrap_or_else(|| {
 1829            cx.new(|cx| {
 1830                DisplayMap::new(
 1831                    buffer.clone(),
 1832                    style.font(),
 1833                    font_size,
 1834                    None,
 1835                    FILE_HEADER_HEIGHT,
 1836                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1837                    fold_placeholder,
 1838                    diagnostics_max_severity,
 1839                    cx,
 1840                )
 1841            })
 1842        });
 1843
 1844        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1845
 1846        let blink_manager = cx.new(|cx| {
 1847            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1848            if is_minimap {
 1849                blink_manager.disable(cx);
 1850            }
 1851            blink_manager
 1852        });
 1853
 1854        let soft_wrap_mode_override =
 1855            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1856
 1857        let mut project_subscriptions = Vec::new();
 1858        if full_mode && let Some(project) = project.as_ref() {
 1859            project_subscriptions.push(cx.subscribe_in(
 1860                project,
 1861                window,
 1862                |editor, _, event, window, cx| match event {
 1863                    project::Event::RefreshCodeLens => {
 1864                        // we always query lens with actions, without storing them, always refreshing them
 1865                    }
 1866                    project::Event::RefreshInlayHints => {
 1867                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1868                    }
 1869                    project::Event::LanguageServerAdded(..)
 1870                    | project::Event::LanguageServerRemoved(..) => {
 1871                        if editor.tasks_update_task.is_none() {
 1872                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1873                        }
 1874                    }
 1875                    project::Event::SnippetEdit(id, snippet_edits) => {
 1876                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                            let focus_handle = editor.focus_handle(cx);
 1878                            if focus_handle.is_focused(window) {
 1879                                let snapshot = buffer.read(cx).snapshot();
 1880                                for (range, snippet) in snippet_edits {
 1881                                    let editor_range =
 1882                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                    editor
 1884                                        .insert_snippet(
 1885                                            &[editor_range],
 1886                                            snippet.clone(),
 1887                                            window,
 1888                                            cx,
 1889                                        )
 1890                                        .ok();
 1891                                }
 1892                            }
 1893                        }
 1894                    }
 1895                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1896                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1897                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1898                        }
 1899                    }
 1900
 1901                    project::Event::EntryRenamed(transaction) => {
 1902                        let Some(workspace) = editor.workspace() else {
 1903                            return;
 1904                        };
 1905                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1906                        else {
 1907                            return;
 1908                        };
 1909                        if active_editor.entity_id() == cx.entity_id() {
 1910                            let edited_buffers_already_open = {
 1911                                let other_editors: Vec<Entity<Editor>> = workspace
 1912                                    .read(cx)
 1913                                    .panes()
 1914                                    .iter()
 1915                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1916                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1917                                    .collect();
 1918
 1919                                transaction.0.keys().all(|buffer| {
 1920                                    other_editors.iter().any(|editor| {
 1921                                        let multi_buffer = editor.read(cx).buffer();
 1922                                        multi_buffer.read(cx).is_singleton()
 1923                                            && multi_buffer.read(cx).as_singleton().map_or(
 1924                                                false,
 1925                                                |singleton| {
 1926                                                    singleton.entity_id() == buffer.entity_id()
 1927                                                },
 1928                                            )
 1929                                    })
 1930                                })
 1931                            };
 1932
 1933                            if !edited_buffers_already_open {
 1934                                let workspace = workspace.downgrade();
 1935                                let transaction = transaction.clone();
 1936                                cx.defer_in(window, move |_, window, cx| {
 1937                                    cx.spawn_in(window, async move |editor, cx| {
 1938                                        Self::open_project_transaction(
 1939                                            &editor,
 1940                                            workspace,
 1941                                            transaction,
 1942                                            "Rename".to_string(),
 1943                                            cx,
 1944                                        )
 1945                                        .await
 1946                                        .ok()
 1947                                    })
 1948                                    .detach();
 1949                                });
 1950                            }
 1951                        }
 1952                    }
 1953
 1954                    _ => {}
 1955                },
 1956            ));
 1957            if let Some(task_inventory) = project
 1958                .read(cx)
 1959                .task_store()
 1960                .read(cx)
 1961                .task_inventory()
 1962                .cloned()
 1963            {
 1964                project_subscriptions.push(cx.observe_in(
 1965                    &task_inventory,
 1966                    window,
 1967                    |editor, _, window, cx| {
 1968                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1969                    },
 1970                ));
 1971            };
 1972
 1973            project_subscriptions.push(cx.subscribe_in(
 1974                &project.read(cx).breakpoint_store(),
 1975                window,
 1976                |editor, _, event, window, cx| match event {
 1977                    BreakpointStoreEvent::ClearDebugLines => {
 1978                        editor.clear_row_highlights::<ActiveDebugLine>();
 1979                        editor.refresh_inline_values(cx);
 1980                    }
 1981                    BreakpointStoreEvent::SetDebugLine => {
 1982                        if editor.go_to_active_debug_line(window, cx) {
 1983                            cx.stop_propagation();
 1984                        }
 1985
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    _ => {}
 1989                },
 1990            ));
 1991            let git_store = project.read(cx).git_store().clone();
 1992            let project = project.clone();
 1993            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1994                if let GitStoreEvent::RepositoryUpdated(
 1995                    _,
 1996                    RepositoryEvent::Updated {
 1997                        new_instance: true, ..
 1998                    },
 1999                    _,
 2000                ) = event
 2001                {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    buffer.read(cx).all_buffers(),
 2054                    buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            placeholder_display_map: None,
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: HashMap::default(),
 2115            gutter_highlights: HashMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144            collapse_matches: false,
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            word_completions_enabled: full_mode,
 2167            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2168            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2169            gutter_hovered: false,
 2170            pixel_position_of_newest_cursor: None,
 2171            last_bounds: None,
 2172            last_position_map: None,
 2173            expect_bounds_change: None,
 2174            gutter_dimensions: GutterDimensions::default(),
 2175            style: None,
 2176            show_cursor_names: false,
 2177            hovered_cursors: HashMap::default(),
 2178            next_editor_action_id: EditorActionId::default(),
 2179            editor_actions: Rc::default(),
 2180            edit_predictions_hidden_for_vim_mode: false,
 2181            show_edit_predictions_override: None,
 2182            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2183            edit_prediction_settings: EditPredictionSettings::Disabled,
 2184            edit_prediction_indent_conflict: false,
 2185            edit_prediction_requires_modifier_in_indent_conflict: true,
 2186            custom_context_menu: None,
 2187            show_git_blame_gutter: false,
 2188            show_git_blame_inline: false,
 2189            show_selection_menu: None,
 2190            show_git_blame_inline_delay_task: None,
 2191            git_blame_inline_enabled: full_mode
 2192                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2193            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2194            serialize_dirty_buffers: !is_minimap
 2195                && ProjectSettings::get_global(cx)
 2196                    .session
 2197                    .restore_unsaved_buffers,
 2198            blame: None,
 2199            blame_subscription: None,
 2200            tasks: BTreeMap::default(),
 2201
 2202            breakpoint_store,
 2203            gutter_breakpoint_indicator: (None, None),
 2204            hovered_diff_hunk_row: None,
 2205            _subscriptions: (!is_minimap)
 2206                .then(|| {
 2207                    vec![
 2208                        cx.observe(&buffer, Self::on_buffer_changed),
 2209                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2210                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2211                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2212                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2213                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2214                        cx.observe_window_activation(window, |editor, window, cx| {
 2215                            let active = window.is_window_active();
 2216                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2217                                if active {
 2218                                    blink_manager.enable(cx);
 2219                                } else {
 2220                                    blink_manager.disable(cx);
 2221                                }
 2222                            });
 2223                            if active {
 2224                                editor.show_mouse_cursor(cx);
 2225                            }
 2226                        }),
 2227                    ]
 2228                })
 2229                .unwrap_or_default(),
 2230            tasks_update_task: None,
 2231            pull_diagnostics_task: Task::ready(()),
 2232            colors: None,
 2233            next_color_inlay_id: 0,
 2234            linked_edit_ranges: Default::default(),
 2235            in_project_search: false,
 2236            previous_search_ranges: None,
 2237            breadcrumb_header: None,
 2238            focused_block: None,
 2239            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2240            addons: HashMap::default(),
 2241            registered_buffers: HashMap::default(),
 2242            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2243            selection_mark_mode: false,
 2244            toggle_fold_multiple_buffers: Task::ready(()),
 2245            serialize_selections: Task::ready(()),
 2246            serialize_folds: Task::ready(()),
 2247            text_style_refinement: None,
 2248            load_diff_task: load_uncommitted_diff,
 2249            temporary_diff_override: false,
 2250            mouse_cursor_hidden: false,
 2251            minimap: None,
 2252            hide_mouse_mode: EditorSettings::get_global(cx)
 2253                .hide_mouse
 2254                .unwrap_or_default(),
 2255            change_list: ChangeList::new(),
 2256            mode,
 2257            selection_drag_state: SelectionDragState::None,
 2258            folding_newlines: Task::ready(()),
 2259            lookup_key: None,
 2260        };
 2261
 2262        if is_minimap {
 2263            return editor;
 2264        }
 2265
 2266        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2267            editor
 2268                ._subscriptions
 2269                .push(cx.observe(breakpoints, |_, _, cx| {
 2270                    cx.notify();
 2271                }));
 2272        }
 2273        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2274        editor._subscriptions.extend(project_subscriptions);
 2275
 2276        editor._subscriptions.push(cx.subscribe_in(
 2277            &cx.entity(),
 2278            window,
 2279            |editor, _, e: &EditorEvent, window, cx| match e {
 2280                EditorEvent::ScrollPositionChanged { local, .. } => {
 2281                    if *local {
 2282                        let new_anchor = editor.scroll_manager.anchor();
 2283                        let snapshot = editor.snapshot(window, cx);
 2284                        editor.update_restoration_data(cx, move |data| {
 2285                            data.scroll_position = (
 2286                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2287                                new_anchor.offset,
 2288                            );
 2289                        });
 2290                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2291                        editor.inline_blame_popover.take();
 2292                    }
 2293                }
 2294                EditorEvent::Edited { .. } => {
 2295                    if !vim_enabled(cx) {
 2296                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            if let Some(buffer) = buffer.read(cx).as_singleton()
 2369                && let Some(project) = editor.project()
 2370            {
 2371                let handle = project.update(cx, |project, cx| {
 2372                    project.register_buffer_with_language_servers(&buffer, cx)
 2373                });
 2374                editor
 2375                    .registered_buffers
 2376                    .insert(buffer.read(cx).remote_id(), handle);
 2377            }
 2378
 2379            editor.minimap =
 2380                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2381            editor.colors = Some(LspColorData::new(cx));
 2382            editor.update_lsp_data(false, None, window, cx);
 2383        }
 2384
 2385        if editor.mode.is_full() {
 2386            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2387        }
 2388
 2389        editor
 2390    }
 2391
 2392    pub fn deploy_mouse_context_menu(
 2393        &mut self,
 2394        position: gpui::Point<Pixels>,
 2395        context_menu: Entity<ContextMenu>,
 2396        window: &mut Window,
 2397        cx: &mut Context<Self>,
 2398    ) {
 2399        self.mouse_context_menu = Some(MouseContextMenu::new(
 2400            self,
 2401            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2402            context_menu,
 2403            window,
 2404            cx,
 2405        ));
 2406    }
 2407
 2408    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2409        self.mouse_context_menu
 2410            .as_ref()
 2411            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2412    }
 2413
 2414    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2415        if self
 2416            .selections
 2417            .pending_anchor()
 2418            .is_some_and(|pending_selection| {
 2419                let snapshot = self.buffer().read(cx).snapshot(cx);
 2420                pending_selection.range().includes(range, &snapshot)
 2421            })
 2422        {
 2423            return true;
 2424        }
 2425
 2426        self.selections
 2427            .disjoint_in_range::<usize>(range.clone(), cx)
 2428            .into_iter()
 2429            .any(|selection| {
 2430                // This is needed to cover a corner case, if we just check for an existing
 2431                // selection in the fold range, having a cursor at the start of the fold
 2432                // marks it as selected. Non-empty selections don't cause this.
 2433                let length = selection.end - selection.start;
 2434                length > 0
 2435            })
 2436    }
 2437
 2438    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2439        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2440    }
 2441
 2442    fn key_context_internal(
 2443        &self,
 2444        has_active_edit_prediction: bool,
 2445        window: &Window,
 2446        cx: &App,
 2447    ) -> KeyContext {
 2448        let mut key_context = KeyContext::new_with_defaults();
 2449        key_context.add("Editor");
 2450        let mode = match self.mode {
 2451            EditorMode::SingleLine => "single_line",
 2452            EditorMode::AutoHeight { .. } => "auto_height",
 2453            EditorMode::Minimap { .. } => "minimap",
 2454            EditorMode::Full { .. } => "full",
 2455        };
 2456
 2457        if EditorSettings::jupyter_enabled(cx) {
 2458            key_context.add("jupyter");
 2459        }
 2460
 2461        key_context.set("mode", mode);
 2462        if self.pending_rename.is_some() {
 2463            key_context.add("renaming");
 2464        }
 2465
 2466        match self.context_menu.borrow().as_ref() {
 2467            Some(CodeContextMenu::Completions(menu)) => {
 2468                if menu.visible() {
 2469                    key_context.add("menu");
 2470                    key_context.add("showing_completions");
 2471                }
 2472            }
 2473            Some(CodeContextMenu::CodeActions(menu)) => {
 2474                if menu.visible() {
 2475                    key_context.add("menu");
 2476                    key_context.add("showing_code_actions")
 2477                }
 2478            }
 2479            None => {}
 2480        }
 2481
 2482        if self.signature_help_state.has_multiple_signatures() {
 2483            key_context.add("showing_signature_help");
 2484        }
 2485
 2486        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2487        if !self.focus_handle(cx).contains_focused(window, cx)
 2488            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2489        {
 2490            for addon in self.addons.values() {
 2491                addon.extend_key_context(&mut key_context, cx)
 2492            }
 2493        }
 2494
 2495        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2496            if let Some(extension) = singleton_buffer
 2497                .read(cx)
 2498                .file()
 2499                .and_then(|file| file.path().extension()?.to_str())
 2500            {
 2501                key_context.set("extension", extension.to_string());
 2502            }
 2503        } else {
 2504            key_context.add("multibuffer");
 2505        }
 2506
 2507        if has_active_edit_prediction {
 2508            if self.edit_prediction_in_conflict() {
 2509                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2510            } else {
 2511                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2512                key_context.add("copilot_suggestion");
 2513            }
 2514        }
 2515
 2516        if self.selection_mark_mode {
 2517            key_context.add("selection_mode");
 2518        }
 2519
 2520        key_context
 2521    }
 2522
 2523    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2524        if self.mouse_cursor_hidden {
 2525            self.mouse_cursor_hidden = false;
 2526            cx.notify();
 2527        }
 2528    }
 2529
 2530    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2531        let hide_mouse_cursor = match origin {
 2532            HideMouseCursorOrigin::TypingAction => {
 2533                matches!(
 2534                    self.hide_mouse_mode,
 2535                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2536                )
 2537            }
 2538            HideMouseCursorOrigin::MovementAction => {
 2539                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2540            }
 2541        };
 2542        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2543            self.mouse_cursor_hidden = hide_mouse_cursor;
 2544            cx.notify();
 2545        }
 2546    }
 2547
 2548    pub fn edit_prediction_in_conflict(&self) -> bool {
 2549        if !self.show_edit_predictions_in_menu() {
 2550            return false;
 2551        }
 2552
 2553        let showing_completions = self
 2554            .context_menu
 2555            .borrow()
 2556            .as_ref()
 2557            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2558
 2559        showing_completions
 2560            || self.edit_prediction_requires_modifier()
 2561            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2562            // bindings to insert tab characters.
 2563            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2564    }
 2565
 2566    pub fn accept_edit_prediction_keybind(
 2567        &self,
 2568        accept_partial: bool,
 2569        window: &Window,
 2570        cx: &App,
 2571    ) -> AcceptEditPredictionBinding {
 2572        let key_context = self.key_context_internal(true, window, cx);
 2573        let in_conflict = self.edit_prediction_in_conflict();
 2574
 2575        let bindings = if accept_partial {
 2576            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2577        } else {
 2578            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2579        };
 2580
 2581        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2582        // just the first one.
 2583        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2584            !in_conflict
 2585                || binding
 2586                    .keystrokes()
 2587                    .first()
 2588                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2589        }))
 2590    }
 2591
 2592    pub fn new_file(
 2593        workspace: &mut Workspace,
 2594        _: &workspace::NewFile,
 2595        window: &mut Window,
 2596        cx: &mut Context<Workspace>,
 2597    ) {
 2598        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2599            "Failed to create buffer",
 2600            window,
 2601            cx,
 2602            |e, _, _| match e.error_code() {
 2603                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2604                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2605                e.error_tag("required").unwrap_or("the latest version")
 2606            )),
 2607                _ => None,
 2608            },
 2609        );
 2610    }
 2611
 2612    pub fn new_in_workspace(
 2613        workspace: &mut Workspace,
 2614        window: &mut Window,
 2615        cx: &mut Context<Workspace>,
 2616    ) -> Task<Result<Entity<Editor>>> {
 2617        let project = workspace.project().clone();
 2618        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2619
 2620        cx.spawn_in(window, async move |workspace, cx| {
 2621            let buffer = create.await?;
 2622            workspace.update_in(cx, |workspace, window, cx| {
 2623                let editor =
 2624                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2625                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2626                editor
 2627            })
 2628        })
 2629    }
 2630
 2631    fn new_file_vertical(
 2632        workspace: &mut Workspace,
 2633        _: &workspace::NewFileSplitVertical,
 2634        window: &mut Window,
 2635        cx: &mut Context<Workspace>,
 2636    ) {
 2637        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2638    }
 2639
 2640    fn new_file_horizontal(
 2641        workspace: &mut Workspace,
 2642        _: &workspace::NewFileSplitHorizontal,
 2643        window: &mut Window,
 2644        cx: &mut Context<Workspace>,
 2645    ) {
 2646        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2647    }
 2648
 2649    fn new_file_in_direction(
 2650        workspace: &mut Workspace,
 2651        direction: SplitDirection,
 2652        window: &mut Window,
 2653        cx: &mut Context<Workspace>,
 2654    ) {
 2655        let project = workspace.project().clone();
 2656        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2657
 2658        cx.spawn_in(window, async move |workspace, cx| {
 2659            let buffer = create.await?;
 2660            workspace.update_in(cx, move |workspace, window, cx| {
 2661                workspace.split_item(
 2662                    direction,
 2663                    Box::new(
 2664                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2665                    ),
 2666                    window,
 2667                    cx,
 2668                )
 2669            })?;
 2670            anyhow::Ok(())
 2671        })
 2672        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2673            match e.error_code() {
 2674                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2675                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2676                e.error_tag("required").unwrap_or("the latest version")
 2677            )),
 2678                _ => None,
 2679            }
 2680        });
 2681    }
 2682
 2683    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2684        self.leader_id
 2685    }
 2686
 2687    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2688        &self.buffer
 2689    }
 2690
 2691    pub fn project(&self) -> Option<&Entity<Project>> {
 2692        self.project.as_ref()
 2693    }
 2694
 2695    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2696        self.workspace.as_ref()?.0.upgrade()
 2697    }
 2698
 2699    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2700        self.buffer().read(cx).title(cx)
 2701    }
 2702
 2703    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2704        let git_blame_gutter_max_author_length = self
 2705            .render_git_blame_gutter(cx)
 2706            .then(|| {
 2707                if let Some(blame) = self.blame.as_ref() {
 2708                    let max_author_length =
 2709                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2710                    Some(max_author_length)
 2711                } else {
 2712                    None
 2713                }
 2714            })
 2715            .flatten();
 2716
 2717        EditorSnapshot {
 2718            mode: self.mode.clone(),
 2719            show_gutter: self.show_gutter,
 2720            show_line_numbers: self.show_line_numbers,
 2721            show_git_diff_gutter: self.show_git_diff_gutter,
 2722            show_code_actions: self.show_code_actions,
 2723            show_runnables: self.show_runnables,
 2724            show_breakpoints: self.show_breakpoints,
 2725            git_blame_gutter_max_author_length,
 2726            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2727            placeholder_display_snapshot: self
 2728                .placeholder_display_map
 2729                .as_ref()
 2730                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2731            scroll_anchor: self.scroll_manager.anchor(),
 2732            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2733            is_focused: self.focus_handle.is_focused(window),
 2734            current_line_highlight: self
 2735                .current_line_highlight
 2736                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2737            gutter_hovered: self.gutter_hovered,
 2738        }
 2739    }
 2740
 2741    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2742        self.buffer.read(cx).language_at(point, cx)
 2743    }
 2744
 2745    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2746        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2747    }
 2748
 2749    pub fn active_excerpt(
 2750        &self,
 2751        cx: &App,
 2752    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2753        self.buffer
 2754            .read(cx)
 2755            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2756    }
 2757
 2758    pub fn mode(&self) -> &EditorMode {
 2759        &self.mode
 2760    }
 2761
 2762    pub fn set_mode(&mut self, mode: EditorMode) {
 2763        self.mode = mode;
 2764    }
 2765
 2766    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2767        self.collaboration_hub.as_deref()
 2768    }
 2769
 2770    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2771        self.collaboration_hub = Some(hub);
 2772    }
 2773
 2774    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2775        self.in_project_search = in_project_search;
 2776    }
 2777
 2778    pub fn set_custom_context_menu(
 2779        &mut self,
 2780        f: impl 'static
 2781        + Fn(
 2782            &mut Self,
 2783            DisplayPoint,
 2784            &mut Window,
 2785            &mut Context<Self>,
 2786        ) -> Option<Entity<ui::ContextMenu>>,
 2787    ) {
 2788        self.custom_context_menu = Some(Box::new(f))
 2789    }
 2790
 2791    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2792        self.completion_provider = provider;
 2793    }
 2794
 2795    #[cfg(any(test, feature = "test-support"))]
 2796    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2797        self.completion_provider.clone()
 2798    }
 2799
 2800    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2801        self.semantics_provider.clone()
 2802    }
 2803
 2804    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2805        self.semantics_provider = provider;
 2806    }
 2807
 2808    pub fn set_edit_prediction_provider<T>(
 2809        &mut self,
 2810        provider: Option<Entity<T>>,
 2811        window: &mut Window,
 2812        cx: &mut Context<Self>,
 2813    ) where
 2814        T: EditPredictionProvider,
 2815    {
 2816        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2817            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2818                if this.focus_handle.is_focused(window) {
 2819                    this.update_visible_edit_prediction(window, cx);
 2820                }
 2821            }),
 2822            provider: Arc::new(provider),
 2823        });
 2824        self.update_edit_prediction_settings(cx);
 2825        self.refresh_edit_prediction(false, false, window, cx);
 2826    }
 2827
 2828    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2829        self.placeholder_display_map
 2830            .as_ref()
 2831            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2832    }
 2833
 2834    pub fn set_placeholder_text(
 2835        &mut self,
 2836        placeholder_text: &str,
 2837        window: &mut Window,
 2838        cx: &mut Context<Self>,
 2839    ) {
 2840        let multibuffer = cx
 2841            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2842
 2843        let style = window.text_style();
 2844
 2845        self.placeholder_display_map = Some(cx.new(|cx| {
 2846            DisplayMap::new(
 2847                multibuffer,
 2848                style.font(),
 2849                style.font_size.to_pixels(window.rem_size()),
 2850                None,
 2851                FILE_HEADER_HEIGHT,
 2852                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2853                Default::default(),
 2854                DiagnosticSeverity::Off,
 2855                cx,
 2856            )
 2857        }));
 2858        cx.notify();
 2859    }
 2860
 2861    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2862        self.cursor_shape = cursor_shape;
 2863
 2864        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2865        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2866
 2867        cx.notify();
 2868    }
 2869
 2870    pub fn set_current_line_highlight(
 2871        &mut self,
 2872        current_line_highlight: Option<CurrentLineHighlight>,
 2873    ) {
 2874        self.current_line_highlight = current_line_highlight;
 2875    }
 2876
 2877    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2878        self.collapse_matches = collapse_matches;
 2879    }
 2880
 2881    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2882        let buffers = self.buffer.read(cx).all_buffers();
 2883        let Some(project) = self.project.as_ref() else {
 2884            return;
 2885        };
 2886        project.update(cx, |project, cx| {
 2887            for buffer in buffers {
 2888                self.registered_buffers
 2889                    .entry(buffer.read(cx).remote_id())
 2890                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2891            }
 2892        })
 2893    }
 2894
 2895    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2896        if self.collapse_matches {
 2897            return range.start..range.start;
 2898        }
 2899        range.clone()
 2900    }
 2901
 2902    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2903        if self.display_map.read(cx).clip_at_line_ends != clip {
 2904            self.display_map
 2905                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2906        }
 2907    }
 2908
 2909    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2910        self.input_enabled = input_enabled;
 2911    }
 2912
 2913    pub fn set_edit_predictions_hidden_for_vim_mode(
 2914        &mut self,
 2915        hidden: bool,
 2916        window: &mut Window,
 2917        cx: &mut Context<Self>,
 2918    ) {
 2919        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2920            self.edit_predictions_hidden_for_vim_mode = hidden;
 2921            if hidden {
 2922                self.update_visible_edit_prediction(window, cx);
 2923            } else {
 2924                self.refresh_edit_prediction(true, false, window, cx);
 2925            }
 2926        }
 2927    }
 2928
 2929    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2930        self.menu_edit_predictions_policy = value;
 2931    }
 2932
 2933    pub fn set_autoindent(&mut self, autoindent: bool) {
 2934        if autoindent {
 2935            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2936        } else {
 2937            self.autoindent_mode = None;
 2938        }
 2939    }
 2940
 2941    pub fn read_only(&self, cx: &App) -> bool {
 2942        self.read_only || self.buffer.read(cx).read_only()
 2943    }
 2944
 2945    pub fn set_read_only(&mut self, read_only: bool) {
 2946        self.read_only = read_only;
 2947    }
 2948
 2949    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2950        self.use_autoclose = autoclose;
 2951    }
 2952
 2953    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2954        self.use_auto_surround = auto_surround;
 2955    }
 2956
 2957    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2958        self.auto_replace_emoji_shortcode = auto_replace;
 2959    }
 2960
 2961    pub fn toggle_edit_predictions(
 2962        &mut self,
 2963        _: &ToggleEditPrediction,
 2964        window: &mut Window,
 2965        cx: &mut Context<Self>,
 2966    ) {
 2967        if self.show_edit_predictions_override.is_some() {
 2968            self.set_show_edit_predictions(None, window, cx);
 2969        } else {
 2970            let show_edit_predictions = !self.edit_predictions_enabled();
 2971            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2972        }
 2973    }
 2974
 2975    pub fn set_show_edit_predictions(
 2976        &mut self,
 2977        show_edit_predictions: Option<bool>,
 2978        window: &mut Window,
 2979        cx: &mut Context<Self>,
 2980    ) {
 2981        self.show_edit_predictions_override = show_edit_predictions;
 2982        self.update_edit_prediction_settings(cx);
 2983
 2984        if let Some(false) = show_edit_predictions {
 2985            self.discard_edit_prediction(false, cx);
 2986        } else {
 2987            self.refresh_edit_prediction(false, true, window, cx);
 2988        }
 2989    }
 2990
 2991    fn edit_predictions_disabled_in_scope(
 2992        &self,
 2993        buffer: &Entity<Buffer>,
 2994        buffer_position: language::Anchor,
 2995        cx: &App,
 2996    ) -> bool {
 2997        let snapshot = buffer.read(cx).snapshot();
 2998        let settings = snapshot.settings_at(buffer_position, cx);
 2999
 3000        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3001            return false;
 3002        };
 3003
 3004        scope.override_name().is_some_and(|scope_name| {
 3005            settings
 3006                .edit_predictions_disabled_in
 3007                .iter()
 3008                .any(|s| s == scope_name)
 3009        })
 3010    }
 3011
 3012    pub fn set_use_modal_editing(&mut self, to: bool) {
 3013        self.use_modal_editing = to;
 3014    }
 3015
 3016    pub fn use_modal_editing(&self) -> bool {
 3017        self.use_modal_editing
 3018    }
 3019
 3020    fn selections_did_change(
 3021        &mut self,
 3022        local: bool,
 3023        old_cursor_position: &Anchor,
 3024        effects: SelectionEffects,
 3025        window: &mut Window,
 3026        cx: &mut Context<Self>,
 3027    ) {
 3028        window.invalidate_character_coordinates();
 3029
 3030        // Copy selections to primary selection buffer
 3031        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3032        if local {
 3033            let selections = self.selections.all::<usize>(cx);
 3034            let buffer_handle = self.buffer.read(cx).read(cx);
 3035
 3036            let mut text = String::new();
 3037            for (index, selection) in selections.iter().enumerate() {
 3038                let text_for_selection = buffer_handle
 3039                    .text_for_range(selection.start..selection.end)
 3040                    .collect::<String>();
 3041
 3042                text.push_str(&text_for_selection);
 3043                if index != selections.len() - 1 {
 3044                    text.push('\n');
 3045                }
 3046            }
 3047
 3048            if !text.is_empty() {
 3049                cx.write_to_primary(ClipboardItem::new_string(text));
 3050            }
 3051        }
 3052
 3053        let selection_anchors = self.selections.disjoint_anchors_arc();
 3054
 3055        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3056            self.buffer.update(cx, |buffer, cx| {
 3057                buffer.set_active_selections(
 3058                    &selection_anchors,
 3059                    self.selections.line_mode,
 3060                    self.cursor_shape,
 3061                    cx,
 3062                )
 3063            });
 3064        }
 3065        let display_map = self
 3066            .display_map
 3067            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3068        let buffer = &display_map.buffer_snapshot;
 3069        if self.selections.count() == 1 {
 3070            self.add_selections_state = None;
 3071        }
 3072        self.select_next_state = None;
 3073        self.select_prev_state = None;
 3074        self.select_syntax_node_history.try_clear();
 3075        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3076        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3077        self.take_rename(false, window, cx);
 3078
 3079        let newest_selection = self.selections.newest_anchor();
 3080        let new_cursor_position = newest_selection.head();
 3081        let selection_start = newest_selection.start;
 3082
 3083        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3084            self.push_to_nav_history(
 3085                *old_cursor_position,
 3086                Some(new_cursor_position.to_point(buffer)),
 3087                false,
 3088                effects.nav_history == Some(true),
 3089                cx,
 3090            );
 3091        }
 3092
 3093        if local {
 3094            if let Some(buffer_id) = new_cursor_position.buffer_id
 3095                && !self.registered_buffers.contains_key(&buffer_id)
 3096                && let Some(project) = self.project.as_ref()
 3097            {
 3098                project.update(cx, |project, cx| {
 3099                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3100                        return;
 3101                    };
 3102                    self.registered_buffers.insert(
 3103                        buffer_id,
 3104                        project.register_buffer_with_language_servers(&buffer, cx),
 3105                    );
 3106                })
 3107            }
 3108
 3109            let mut context_menu = self.context_menu.borrow_mut();
 3110            let completion_menu = match context_menu.as_ref() {
 3111                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3112                Some(CodeContextMenu::CodeActions(_)) => {
 3113                    *context_menu = None;
 3114                    None
 3115                }
 3116                None => None,
 3117            };
 3118            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3119            drop(context_menu);
 3120
 3121            if effects.completions
 3122                && let Some(completion_position) = completion_position
 3123            {
 3124                let start_offset = selection_start.to_offset(buffer);
 3125                let position_matches = start_offset == completion_position.to_offset(buffer);
 3126                let continue_showing = if position_matches {
 3127                    if self.snippet_stack.is_empty() {
 3128                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3129                    } else {
 3130                        // Snippet choices can be shown even when the cursor is in whitespace.
 3131                        // Dismissing the menu with actions like backspace is handled by
 3132                        // invalidation regions.
 3133                        true
 3134                    }
 3135                } else {
 3136                    false
 3137                };
 3138
 3139                if continue_showing {
 3140                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3141                } else {
 3142                    self.hide_context_menu(window, cx);
 3143                }
 3144            }
 3145
 3146            hide_hover(self, cx);
 3147
 3148            if old_cursor_position.to_display_point(&display_map).row()
 3149                != new_cursor_position.to_display_point(&display_map).row()
 3150            {
 3151                self.available_code_actions.take();
 3152            }
 3153            self.refresh_code_actions(window, cx);
 3154            self.refresh_document_highlights(cx);
 3155            self.refresh_selected_text_highlights(false, window, cx);
 3156            refresh_matching_bracket_highlights(self, window, cx);
 3157            self.update_visible_edit_prediction(window, cx);
 3158            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3159            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3160            self.inline_blame_popover.take();
 3161            if self.git_blame_inline_enabled {
 3162                self.start_inline_blame_timer(window, cx);
 3163            }
 3164        }
 3165
 3166        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3167        cx.emit(EditorEvent::SelectionsChanged { local });
 3168
 3169        let selections = &self.selections.disjoint_anchors_arc();
 3170        if selections.len() == 1 {
 3171            cx.emit(SearchEvent::ActiveMatchChanged)
 3172        }
 3173        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3174            let inmemory_selections = selections
 3175                .iter()
 3176                .map(|s| {
 3177                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3178                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3179                })
 3180                .collect();
 3181            self.update_restoration_data(cx, |data| {
 3182                data.selections = inmemory_selections;
 3183            });
 3184
 3185            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3186                && let Some(workspace_id) =
 3187                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3188            {
 3189                let snapshot = self.buffer().read(cx).snapshot(cx);
 3190                let selections = selections.clone();
 3191                let background_executor = cx.background_executor().clone();
 3192                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3193                self.serialize_selections = cx.background_spawn(async move {
 3194                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3195                            let db_selections = selections
 3196                                .iter()
 3197                                .map(|selection| {
 3198                                    (
 3199                                        selection.start.to_offset(&snapshot),
 3200                                        selection.end.to_offset(&snapshot),
 3201                                    )
 3202                                })
 3203                                .collect();
 3204
 3205                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3206                                .await
 3207                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3208                                .log_err();
 3209                        });
 3210            }
 3211        }
 3212
 3213        cx.notify();
 3214    }
 3215
 3216    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3217        use text::ToOffset as _;
 3218        use text::ToPoint as _;
 3219
 3220        if self.mode.is_minimap()
 3221            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3222        {
 3223            return;
 3224        }
 3225
 3226        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3227            return;
 3228        };
 3229
 3230        let snapshot = singleton.read(cx).snapshot();
 3231        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3232            let display_snapshot = display_map.snapshot(cx);
 3233
 3234            display_snapshot
 3235                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3236                .map(|fold| {
 3237                    fold.range.start.text_anchor.to_point(&snapshot)
 3238                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3239                })
 3240                .collect()
 3241        });
 3242        self.update_restoration_data(cx, |data| {
 3243            data.folds = inmemory_folds;
 3244        });
 3245
 3246        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3247            return;
 3248        };
 3249        let background_executor = cx.background_executor().clone();
 3250        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3251        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3252            display_map
 3253                .snapshot(cx)
 3254                .folds_in_range(0..snapshot.len())
 3255                .map(|fold| {
 3256                    (
 3257                        fold.range.start.text_anchor.to_offset(&snapshot),
 3258                        fold.range.end.text_anchor.to_offset(&snapshot),
 3259                    )
 3260                })
 3261                .collect()
 3262        });
 3263        self.serialize_folds = cx.background_spawn(async move {
 3264            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3265            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3266                .await
 3267                .with_context(|| {
 3268                    format!(
 3269                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3270                    )
 3271                })
 3272                .log_err();
 3273        });
 3274    }
 3275
 3276    pub fn sync_selections(
 3277        &mut self,
 3278        other: Entity<Editor>,
 3279        cx: &mut Context<Self>,
 3280    ) -> gpui::Subscription {
 3281        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3282        self.selections.change_with(cx, |selections| {
 3283            selections.select_anchors(other_selections);
 3284        });
 3285
 3286        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3287            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3288                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3289                if other_selections.is_empty() {
 3290                    return;
 3291                }
 3292                this.selections.change_with(cx, |selections| {
 3293                    selections.select_anchors(other_selections);
 3294                });
 3295            }
 3296        });
 3297
 3298        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3299            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3300                let these_selections = this.selections.disjoint_anchors().to_vec();
 3301                if these_selections.is_empty() {
 3302                    return;
 3303                }
 3304                other.update(cx, |other_editor, cx| {
 3305                    other_editor.selections.change_with(cx, |selections| {
 3306                        selections.select_anchors(these_selections);
 3307                    })
 3308                });
 3309            }
 3310        });
 3311
 3312        Subscription::join(other_subscription, this_subscription)
 3313    }
 3314
 3315    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3316    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3317    /// effects of selection change occur at the end of the transaction.
 3318    pub fn change_selections<R>(
 3319        &mut self,
 3320        effects: SelectionEffects,
 3321        window: &mut Window,
 3322        cx: &mut Context<Self>,
 3323        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3324    ) -> R {
 3325        if let Some(state) = &mut self.deferred_selection_effects_state {
 3326            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3327            state.effects.completions = effects.completions;
 3328            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3329            let (changed, result) = self.selections.change_with(cx, change);
 3330            state.changed |= changed;
 3331            return result;
 3332        }
 3333        let mut state = DeferredSelectionEffectsState {
 3334            changed: false,
 3335            effects,
 3336            old_cursor_position: self.selections.newest_anchor().head(),
 3337            history_entry: SelectionHistoryEntry {
 3338                selections: self.selections.disjoint_anchors_arc(),
 3339                select_next_state: self.select_next_state.clone(),
 3340                select_prev_state: self.select_prev_state.clone(),
 3341                add_selections_state: self.add_selections_state.clone(),
 3342            },
 3343        };
 3344        let (changed, result) = self.selections.change_with(cx, change);
 3345        state.changed = state.changed || changed;
 3346        if self.defer_selection_effects {
 3347            self.deferred_selection_effects_state = Some(state);
 3348        } else {
 3349            self.apply_selection_effects(state, window, cx);
 3350        }
 3351        result
 3352    }
 3353
 3354    /// Defers the effects of selection change, so that the effects of multiple calls to
 3355    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3356    /// to selection history and the state of popovers based on selection position aren't
 3357    /// erroneously updated.
 3358    pub fn with_selection_effects_deferred<R>(
 3359        &mut self,
 3360        window: &mut Window,
 3361        cx: &mut Context<Self>,
 3362        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3363    ) -> R {
 3364        let already_deferred = self.defer_selection_effects;
 3365        self.defer_selection_effects = true;
 3366        let result = update(self, window, cx);
 3367        if !already_deferred {
 3368            self.defer_selection_effects = false;
 3369            if let Some(state) = self.deferred_selection_effects_state.take() {
 3370                self.apply_selection_effects(state, window, cx);
 3371            }
 3372        }
 3373        result
 3374    }
 3375
 3376    fn apply_selection_effects(
 3377        &mut self,
 3378        state: DeferredSelectionEffectsState,
 3379        window: &mut Window,
 3380        cx: &mut Context<Self>,
 3381    ) {
 3382        if state.changed {
 3383            self.selection_history.push(state.history_entry);
 3384
 3385            if let Some(autoscroll) = state.effects.scroll {
 3386                self.request_autoscroll(autoscroll, cx);
 3387            }
 3388
 3389            let old_cursor_position = &state.old_cursor_position;
 3390
 3391            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3392
 3393            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3394                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3395            }
 3396        }
 3397    }
 3398
 3399    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3400    where
 3401        I: IntoIterator<Item = (Range<S>, T)>,
 3402        S: ToOffset,
 3403        T: Into<Arc<str>>,
 3404    {
 3405        if self.read_only(cx) {
 3406            return;
 3407        }
 3408
 3409        self.buffer
 3410            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3411    }
 3412
 3413    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3414    where
 3415        I: IntoIterator<Item = (Range<S>, T)>,
 3416        S: ToOffset,
 3417        T: Into<Arc<str>>,
 3418    {
 3419        if self.read_only(cx) {
 3420            return;
 3421        }
 3422
 3423        self.buffer.update(cx, |buffer, cx| {
 3424            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3425        });
 3426    }
 3427
 3428    pub fn edit_with_block_indent<I, S, T>(
 3429        &mut self,
 3430        edits: I,
 3431        original_indent_columns: Vec<Option<u32>>,
 3432        cx: &mut Context<Self>,
 3433    ) where
 3434        I: IntoIterator<Item = (Range<S>, T)>,
 3435        S: ToOffset,
 3436        T: Into<Arc<str>>,
 3437    {
 3438        if self.read_only(cx) {
 3439            return;
 3440        }
 3441
 3442        self.buffer.update(cx, |buffer, cx| {
 3443            buffer.edit(
 3444                edits,
 3445                Some(AutoindentMode::Block {
 3446                    original_indent_columns,
 3447                }),
 3448                cx,
 3449            )
 3450        });
 3451    }
 3452
 3453    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3454        self.hide_context_menu(window, cx);
 3455
 3456        match phase {
 3457            SelectPhase::Begin {
 3458                position,
 3459                add,
 3460                click_count,
 3461            } => self.begin_selection(position, add, click_count, window, cx),
 3462            SelectPhase::BeginColumnar {
 3463                position,
 3464                goal_column,
 3465                reset,
 3466                mode,
 3467            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3468            SelectPhase::Extend {
 3469                position,
 3470                click_count,
 3471            } => self.extend_selection(position, click_count, window, cx),
 3472            SelectPhase::Update {
 3473                position,
 3474                goal_column,
 3475                scroll_delta,
 3476            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3477            SelectPhase::End => self.end_selection(window, cx),
 3478        }
 3479    }
 3480
 3481    fn extend_selection(
 3482        &mut self,
 3483        position: DisplayPoint,
 3484        click_count: usize,
 3485        window: &mut Window,
 3486        cx: &mut Context<Self>,
 3487    ) {
 3488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3489        let tail = self.selections.newest::<usize>(cx).tail();
 3490        self.begin_selection(position, false, click_count, window, cx);
 3491
 3492        let position = position.to_offset(&display_map, Bias::Left);
 3493        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3494
 3495        let mut pending_selection = self
 3496            .selections
 3497            .pending_anchor()
 3498            .cloned()
 3499            .expect("extend_selection not called with pending selection");
 3500        if position >= tail {
 3501            pending_selection.start = tail_anchor;
 3502        } else {
 3503            pending_selection.end = tail_anchor;
 3504            pending_selection.reversed = true;
 3505        }
 3506
 3507        let mut pending_mode = self.selections.pending_mode().unwrap();
 3508        match &mut pending_mode {
 3509            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3510            _ => {}
 3511        }
 3512
 3513        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3514            SelectionEffects::scroll(Autoscroll::fit())
 3515        } else {
 3516            SelectionEffects::no_scroll()
 3517        };
 3518
 3519        self.change_selections(effects, window, cx, |s| {
 3520            s.set_pending(pending_selection.clone(), pending_mode)
 3521        });
 3522    }
 3523
 3524    fn begin_selection(
 3525        &mut self,
 3526        position: DisplayPoint,
 3527        add: bool,
 3528        click_count: usize,
 3529        window: &mut Window,
 3530        cx: &mut Context<Self>,
 3531    ) {
 3532        if !self.focus_handle.is_focused(window) {
 3533            self.last_focused_descendant = None;
 3534            window.focus(&self.focus_handle);
 3535        }
 3536
 3537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3538        let buffer = &display_map.buffer_snapshot;
 3539        let position = display_map.clip_point(position, Bias::Left);
 3540
 3541        let start;
 3542        let end;
 3543        let mode;
 3544        let mut auto_scroll;
 3545        match click_count {
 3546            1 => {
 3547                start = buffer.anchor_before(position.to_point(&display_map));
 3548                end = start;
 3549                mode = SelectMode::Character;
 3550                auto_scroll = true;
 3551            }
 3552            2 => {
 3553                let position = display_map
 3554                    .clip_point(position, Bias::Left)
 3555                    .to_offset(&display_map, Bias::Left);
 3556                let (range, _) = buffer.surrounding_word(position, false);
 3557                start = buffer.anchor_before(range.start);
 3558                end = buffer.anchor_before(range.end);
 3559                mode = SelectMode::Word(start..end);
 3560                auto_scroll = true;
 3561            }
 3562            3 => {
 3563                let position = display_map
 3564                    .clip_point(position, Bias::Left)
 3565                    .to_point(&display_map);
 3566                let line_start = display_map.prev_line_boundary(position).0;
 3567                let next_line_start = buffer.clip_point(
 3568                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3569                    Bias::Left,
 3570                );
 3571                start = buffer.anchor_before(line_start);
 3572                end = buffer.anchor_before(next_line_start);
 3573                mode = SelectMode::Line(start..end);
 3574                auto_scroll = true;
 3575            }
 3576            _ => {
 3577                start = buffer.anchor_before(0);
 3578                end = buffer.anchor_before(buffer.len());
 3579                mode = SelectMode::All;
 3580                auto_scroll = false;
 3581            }
 3582        }
 3583        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3584
 3585        let point_to_delete: Option<usize> = {
 3586            let selected_points: Vec<Selection<Point>> =
 3587                self.selections.disjoint_in_range(start..end, cx);
 3588
 3589            if !add || click_count > 1 {
 3590                None
 3591            } else if !selected_points.is_empty() {
 3592                Some(selected_points[0].id)
 3593            } else {
 3594                let clicked_point_already_selected =
 3595                    self.selections.disjoint_anchors().iter().find(|selection| {
 3596                        selection.start.to_point(buffer) == start.to_point(buffer)
 3597                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3598                    });
 3599
 3600                clicked_point_already_selected.map(|selection| selection.id)
 3601            }
 3602        };
 3603
 3604        let selections_count = self.selections.count();
 3605        let effects = if auto_scroll {
 3606            SelectionEffects::default()
 3607        } else {
 3608            SelectionEffects::no_scroll()
 3609        };
 3610
 3611        self.change_selections(effects, window, cx, |s| {
 3612            if let Some(point_to_delete) = point_to_delete {
 3613                s.delete(point_to_delete);
 3614
 3615                if selections_count == 1 {
 3616                    s.set_pending_anchor_range(start..end, mode);
 3617                }
 3618            } else {
 3619                if !add {
 3620                    s.clear_disjoint();
 3621                }
 3622
 3623                s.set_pending_anchor_range(start..end, mode);
 3624            }
 3625        });
 3626    }
 3627
 3628    fn begin_columnar_selection(
 3629        &mut self,
 3630        position: DisplayPoint,
 3631        goal_column: u32,
 3632        reset: bool,
 3633        mode: ColumnarMode,
 3634        window: &mut Window,
 3635        cx: &mut Context<Self>,
 3636    ) {
 3637        if !self.focus_handle.is_focused(window) {
 3638            self.last_focused_descendant = None;
 3639            window.focus(&self.focus_handle);
 3640        }
 3641
 3642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3643
 3644        if reset {
 3645            let pointer_position = display_map
 3646                .buffer_snapshot
 3647                .anchor_before(position.to_point(&display_map));
 3648
 3649            self.change_selections(
 3650                SelectionEffects::scroll(Autoscroll::newest()),
 3651                window,
 3652                cx,
 3653                |s| {
 3654                    s.clear_disjoint();
 3655                    s.set_pending_anchor_range(
 3656                        pointer_position..pointer_position,
 3657                        SelectMode::Character,
 3658                    );
 3659                },
 3660            );
 3661        };
 3662
 3663        let tail = self.selections.newest::<Point>(cx).tail();
 3664        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3665        self.columnar_selection_state = match mode {
 3666            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3667                selection_tail: selection_anchor,
 3668                display_point: if reset {
 3669                    if position.column() != goal_column {
 3670                        Some(DisplayPoint::new(position.row(), goal_column))
 3671                    } else {
 3672                        None
 3673                    }
 3674                } else {
 3675                    None
 3676                },
 3677            }),
 3678            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3679                selection_tail: selection_anchor,
 3680            }),
 3681        };
 3682
 3683        if !reset {
 3684            self.select_columns(position, goal_column, &display_map, window, cx);
 3685        }
 3686    }
 3687
 3688    fn update_selection(
 3689        &mut self,
 3690        position: DisplayPoint,
 3691        goal_column: u32,
 3692        scroll_delta: gpui::Point<f32>,
 3693        window: &mut Window,
 3694        cx: &mut Context<Self>,
 3695    ) {
 3696        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3697
 3698        if self.columnar_selection_state.is_some() {
 3699            self.select_columns(position, goal_column, &display_map, window, cx);
 3700        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3701            let buffer = &display_map.buffer_snapshot;
 3702            let head;
 3703            let tail;
 3704            let mode = self.selections.pending_mode().unwrap();
 3705            match &mode {
 3706                SelectMode::Character => {
 3707                    head = position.to_point(&display_map);
 3708                    tail = pending.tail().to_point(buffer);
 3709                }
 3710                SelectMode::Word(original_range) => {
 3711                    let offset = display_map
 3712                        .clip_point(position, Bias::Left)
 3713                        .to_offset(&display_map, Bias::Left);
 3714                    let original_range = original_range.to_offset(buffer);
 3715
 3716                    let head_offset = if buffer.is_inside_word(offset, false)
 3717                        || original_range.contains(&offset)
 3718                    {
 3719                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3720                        if word_range.start < original_range.start {
 3721                            word_range.start
 3722                        } else {
 3723                            word_range.end
 3724                        }
 3725                    } else {
 3726                        offset
 3727                    };
 3728
 3729                    head = head_offset.to_point(buffer);
 3730                    if head_offset <= original_range.start {
 3731                        tail = original_range.end.to_point(buffer);
 3732                    } else {
 3733                        tail = original_range.start.to_point(buffer);
 3734                    }
 3735                }
 3736                SelectMode::Line(original_range) => {
 3737                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3738
 3739                    let position = display_map
 3740                        .clip_point(position, Bias::Left)
 3741                        .to_point(&display_map);
 3742                    let line_start = display_map.prev_line_boundary(position).0;
 3743                    let next_line_start = buffer.clip_point(
 3744                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3745                        Bias::Left,
 3746                    );
 3747
 3748                    if line_start < original_range.start {
 3749                        head = line_start
 3750                    } else {
 3751                        head = next_line_start
 3752                    }
 3753
 3754                    if head <= original_range.start {
 3755                        tail = original_range.end;
 3756                    } else {
 3757                        tail = original_range.start;
 3758                    }
 3759                }
 3760                SelectMode::All => {
 3761                    return;
 3762                }
 3763            };
 3764
 3765            if head < tail {
 3766                pending.start = buffer.anchor_before(head);
 3767                pending.end = buffer.anchor_before(tail);
 3768                pending.reversed = true;
 3769            } else {
 3770                pending.start = buffer.anchor_before(tail);
 3771                pending.end = buffer.anchor_before(head);
 3772                pending.reversed = false;
 3773            }
 3774
 3775            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3776                s.set_pending(pending.clone(), mode);
 3777            });
 3778        } else {
 3779            log::error!("update_selection dispatched with no pending selection");
 3780            return;
 3781        }
 3782
 3783        self.apply_scroll_delta(scroll_delta, window, cx);
 3784        cx.notify();
 3785    }
 3786
 3787    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3788        self.columnar_selection_state.take();
 3789        if self.selections.pending_anchor().is_some() {
 3790            let selections = self.selections.all::<usize>(cx);
 3791            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3792                s.select(selections);
 3793                s.clear_pending();
 3794            });
 3795        }
 3796    }
 3797
 3798    fn select_columns(
 3799        &mut self,
 3800        head: DisplayPoint,
 3801        goal_column: u32,
 3802        display_map: &DisplaySnapshot,
 3803        window: &mut Window,
 3804        cx: &mut Context<Self>,
 3805    ) {
 3806        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3807            return;
 3808        };
 3809
 3810        let tail = match columnar_state {
 3811            ColumnarSelectionState::FromMouse {
 3812                selection_tail,
 3813                display_point,
 3814            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3815            ColumnarSelectionState::FromSelection { selection_tail } => {
 3816                selection_tail.to_display_point(display_map)
 3817            }
 3818        };
 3819
 3820        let start_row = cmp::min(tail.row(), head.row());
 3821        let end_row = cmp::max(tail.row(), head.row());
 3822        let start_column = cmp::min(tail.column(), goal_column);
 3823        let end_column = cmp::max(tail.column(), goal_column);
 3824        let reversed = start_column < tail.column();
 3825
 3826        let selection_ranges = (start_row.0..=end_row.0)
 3827            .map(DisplayRow)
 3828            .filter_map(|row| {
 3829                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3830                    || start_column <= display_map.line_len(row))
 3831                    && !display_map.is_block_line(row)
 3832                {
 3833                    let start = display_map
 3834                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3835                        .to_point(display_map);
 3836                    let end = display_map
 3837                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3838                        .to_point(display_map);
 3839                    if reversed {
 3840                        Some(end..start)
 3841                    } else {
 3842                        Some(start..end)
 3843                    }
 3844                } else {
 3845                    None
 3846                }
 3847            })
 3848            .collect::<Vec<_>>();
 3849
 3850        let ranges = match columnar_state {
 3851            ColumnarSelectionState::FromMouse { .. } => {
 3852                let mut non_empty_ranges = selection_ranges
 3853                    .iter()
 3854                    .filter(|selection_range| selection_range.start != selection_range.end)
 3855                    .peekable();
 3856                if non_empty_ranges.peek().is_some() {
 3857                    non_empty_ranges.cloned().collect()
 3858                } else {
 3859                    selection_ranges
 3860                }
 3861            }
 3862            _ => selection_ranges,
 3863        };
 3864
 3865        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3866            s.select_ranges(ranges);
 3867        });
 3868        cx.notify();
 3869    }
 3870
 3871    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3872        self.selections
 3873            .all_adjusted(cx)
 3874            .iter()
 3875            .any(|selection| !selection.is_empty())
 3876    }
 3877
 3878    pub fn has_pending_nonempty_selection(&self) -> bool {
 3879        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3880            Some(Selection { start, end, .. }) => start != end,
 3881            None => false,
 3882        };
 3883
 3884        pending_nonempty_selection
 3885            || (self.columnar_selection_state.is_some()
 3886                && self.selections.disjoint_anchors().len() > 1)
 3887    }
 3888
 3889    pub fn has_pending_selection(&self) -> bool {
 3890        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3891    }
 3892
 3893    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3894        self.selection_mark_mode = false;
 3895        self.selection_drag_state = SelectionDragState::None;
 3896
 3897        if self.clear_expanded_diff_hunks(cx) {
 3898            cx.notify();
 3899            return;
 3900        }
 3901        if self.dismiss_menus_and_popups(true, window, cx) {
 3902            return;
 3903        }
 3904
 3905        if self.mode.is_full()
 3906            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3907        {
 3908            return;
 3909        }
 3910
 3911        cx.propagate();
 3912    }
 3913
 3914    pub fn dismiss_menus_and_popups(
 3915        &mut self,
 3916        is_user_requested: bool,
 3917        window: &mut Window,
 3918        cx: &mut Context<Self>,
 3919    ) -> bool {
 3920        if self.take_rename(false, window, cx).is_some() {
 3921            return true;
 3922        }
 3923
 3924        if hide_hover(self, cx) {
 3925            return true;
 3926        }
 3927
 3928        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3929            return true;
 3930        }
 3931
 3932        if self.hide_context_menu(window, cx).is_some() {
 3933            return true;
 3934        }
 3935
 3936        if self.mouse_context_menu.take().is_some() {
 3937            return true;
 3938        }
 3939
 3940        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3941            return true;
 3942        }
 3943
 3944        if self.snippet_stack.pop().is_some() {
 3945            return true;
 3946        }
 3947
 3948        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3949            self.dismiss_diagnostics(cx);
 3950            return true;
 3951        }
 3952
 3953        false
 3954    }
 3955
 3956    fn linked_editing_ranges_for(
 3957        &self,
 3958        selection: Range<text::Anchor>,
 3959        cx: &App,
 3960    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3961        if self.linked_edit_ranges.is_empty() {
 3962            return None;
 3963        }
 3964        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3965            selection.end.buffer_id.and_then(|end_buffer_id| {
 3966                if selection.start.buffer_id != Some(end_buffer_id) {
 3967                    return None;
 3968                }
 3969                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3970                let snapshot = buffer.read(cx).snapshot();
 3971                self.linked_edit_ranges
 3972                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3973                    .map(|ranges| (ranges, snapshot, buffer))
 3974            })?;
 3975        use text::ToOffset as TO;
 3976        // find offset from the start of current range to current cursor position
 3977        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3978
 3979        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3980        let start_difference = start_offset - start_byte_offset;
 3981        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3982        let end_difference = end_offset - start_byte_offset;
 3983        // Current range has associated linked ranges.
 3984        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3985        for range in linked_ranges.iter() {
 3986            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3987            let end_offset = start_offset + end_difference;
 3988            let start_offset = start_offset + start_difference;
 3989            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3990                continue;
 3991            }
 3992            if self.selections.disjoint_anchor_ranges().any(|s| {
 3993                if s.start.buffer_id != selection.start.buffer_id
 3994                    || s.end.buffer_id != selection.end.buffer_id
 3995                {
 3996                    return false;
 3997                }
 3998                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3999                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4000            }) {
 4001                continue;
 4002            }
 4003            let start = buffer_snapshot.anchor_after(start_offset);
 4004            let end = buffer_snapshot.anchor_after(end_offset);
 4005            linked_edits
 4006                .entry(buffer.clone())
 4007                .or_default()
 4008                .push(start..end);
 4009        }
 4010        Some(linked_edits)
 4011    }
 4012
 4013    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4014        let text: Arc<str> = text.into();
 4015
 4016        if self.read_only(cx) {
 4017            return;
 4018        }
 4019
 4020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4021
 4022        let selections = self.selections.all_adjusted(cx);
 4023        let mut bracket_inserted = false;
 4024        let mut edits = Vec::new();
 4025        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4026        let mut new_selections = Vec::with_capacity(selections.len());
 4027        let mut new_autoclose_regions = Vec::new();
 4028        let snapshot = self.buffer.read(cx).read(cx);
 4029        let mut clear_linked_edit_ranges = false;
 4030
 4031        for (selection, autoclose_region) in
 4032            self.selections_with_autoclose_regions(selections, &snapshot)
 4033        {
 4034            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4035                // Determine if the inserted text matches the opening or closing
 4036                // bracket of any of this language's bracket pairs.
 4037                let mut bracket_pair = None;
 4038                let mut is_bracket_pair_start = false;
 4039                let mut is_bracket_pair_end = false;
 4040                if !text.is_empty() {
 4041                    let mut bracket_pair_matching_end = None;
 4042                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4043                    //  and they are removing the character that triggered IME popup.
 4044                    for (pair, enabled) in scope.brackets() {
 4045                        if !pair.close && !pair.surround {
 4046                            continue;
 4047                        }
 4048
 4049                        if enabled && pair.start.ends_with(text.as_ref()) {
 4050                            let prefix_len = pair.start.len() - text.len();
 4051                            let preceding_text_matches_prefix = prefix_len == 0
 4052                                || (selection.start.column >= (prefix_len as u32)
 4053                                    && snapshot.contains_str_at(
 4054                                        Point::new(
 4055                                            selection.start.row,
 4056                                            selection.start.column - (prefix_len as u32),
 4057                                        ),
 4058                                        &pair.start[..prefix_len],
 4059                                    ));
 4060                            if preceding_text_matches_prefix {
 4061                                bracket_pair = Some(pair.clone());
 4062                                is_bracket_pair_start = true;
 4063                                break;
 4064                            }
 4065                        }
 4066                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4067                        {
 4068                            // take first bracket pair matching end, but don't break in case a later bracket
 4069                            // pair matches start
 4070                            bracket_pair_matching_end = Some(pair.clone());
 4071                        }
 4072                    }
 4073                    if let Some(end) = bracket_pair_matching_end
 4074                        && bracket_pair.is_none()
 4075                    {
 4076                        bracket_pair = Some(end);
 4077                        is_bracket_pair_end = true;
 4078                    }
 4079                }
 4080
 4081                if let Some(bracket_pair) = bracket_pair {
 4082                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4083                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4084                    let auto_surround =
 4085                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4086                    if selection.is_empty() {
 4087                        if is_bracket_pair_start {
 4088                            // If the inserted text is a suffix of an opening bracket and the
 4089                            // selection is preceded by the rest of the opening bracket, then
 4090                            // insert the closing bracket.
 4091                            let following_text_allows_autoclose = snapshot
 4092                                .chars_at(selection.start)
 4093                                .next()
 4094                                .is_none_or(|c| scope.should_autoclose_before(c));
 4095
 4096                            let preceding_text_allows_autoclose = selection.start.column == 0
 4097                                || snapshot
 4098                                    .reversed_chars_at(selection.start)
 4099                                    .next()
 4100                                    .is_none_or(|c| {
 4101                                        bracket_pair.start != bracket_pair.end
 4102                                            || !snapshot
 4103                                                .char_classifier_at(selection.start)
 4104                                                .is_word(c)
 4105                                    });
 4106
 4107                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4108                                && bracket_pair.start.len() == 1
 4109                            {
 4110                                let target = bracket_pair.start.chars().next().unwrap();
 4111                                let current_line_count = snapshot
 4112                                    .reversed_chars_at(selection.start)
 4113                                    .take_while(|&c| c != '\n')
 4114                                    .filter(|&c| c == target)
 4115                                    .count();
 4116                                current_line_count % 2 == 1
 4117                            } else {
 4118                                false
 4119                            };
 4120
 4121                            if autoclose
 4122                                && bracket_pair.close
 4123                                && following_text_allows_autoclose
 4124                                && preceding_text_allows_autoclose
 4125                                && !is_closing_quote
 4126                            {
 4127                                let anchor = snapshot.anchor_before(selection.end);
 4128                                new_selections.push((selection.map(|_| anchor), text.len()));
 4129                                new_autoclose_regions.push((
 4130                                    anchor,
 4131                                    text.len(),
 4132                                    selection.id,
 4133                                    bracket_pair.clone(),
 4134                                ));
 4135                                edits.push((
 4136                                    selection.range(),
 4137                                    format!("{}{}", text, bracket_pair.end).into(),
 4138                                ));
 4139                                bracket_inserted = true;
 4140                                continue;
 4141                            }
 4142                        }
 4143
 4144                        if let Some(region) = autoclose_region {
 4145                            // If the selection is followed by an auto-inserted closing bracket,
 4146                            // then don't insert that closing bracket again; just move the selection
 4147                            // past the closing bracket.
 4148                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4149                                && text.as_ref() == region.pair.end.as_str()
 4150                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4151                            if should_skip {
 4152                                let anchor = snapshot.anchor_after(selection.end);
 4153                                new_selections
 4154                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4155                                continue;
 4156                            }
 4157                        }
 4158
 4159                        let always_treat_brackets_as_autoclosed = snapshot
 4160                            .language_settings_at(selection.start, cx)
 4161                            .always_treat_brackets_as_autoclosed;
 4162                        if always_treat_brackets_as_autoclosed
 4163                            && is_bracket_pair_end
 4164                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4165                        {
 4166                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4167                            // and the inserted text is a closing bracket and the selection is followed
 4168                            // by the closing bracket then move the selection past the closing bracket.
 4169                            let anchor = snapshot.anchor_after(selection.end);
 4170                            new_selections.push((selection.map(|_| anchor), text.len()));
 4171                            continue;
 4172                        }
 4173                    }
 4174                    // If an opening bracket is 1 character long and is typed while
 4175                    // text is selected, then surround that text with the bracket pair.
 4176                    else if auto_surround
 4177                        && bracket_pair.surround
 4178                        && is_bracket_pair_start
 4179                        && bracket_pair.start.chars().count() == 1
 4180                    {
 4181                        edits.push((selection.start..selection.start, text.clone()));
 4182                        edits.push((
 4183                            selection.end..selection.end,
 4184                            bracket_pair.end.as_str().into(),
 4185                        ));
 4186                        bracket_inserted = true;
 4187                        new_selections.push((
 4188                            Selection {
 4189                                id: selection.id,
 4190                                start: snapshot.anchor_after(selection.start),
 4191                                end: snapshot.anchor_before(selection.end),
 4192                                reversed: selection.reversed,
 4193                                goal: selection.goal,
 4194                            },
 4195                            0,
 4196                        ));
 4197                        continue;
 4198                    }
 4199                }
 4200            }
 4201
 4202            if self.auto_replace_emoji_shortcode
 4203                && selection.is_empty()
 4204                && text.as_ref().ends_with(':')
 4205                && let Some(possible_emoji_short_code) =
 4206                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4207                && !possible_emoji_short_code.is_empty()
 4208                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4209            {
 4210                let emoji_shortcode_start = Point::new(
 4211                    selection.start.row,
 4212                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4213                );
 4214
 4215                // Remove shortcode from buffer
 4216                edits.push((
 4217                    emoji_shortcode_start..selection.start,
 4218                    "".to_string().into(),
 4219                ));
 4220                new_selections.push((
 4221                    Selection {
 4222                        id: selection.id,
 4223                        start: snapshot.anchor_after(emoji_shortcode_start),
 4224                        end: snapshot.anchor_before(selection.start),
 4225                        reversed: selection.reversed,
 4226                        goal: selection.goal,
 4227                    },
 4228                    0,
 4229                ));
 4230
 4231                // Insert emoji
 4232                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4233                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4234                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4235
 4236                continue;
 4237            }
 4238
 4239            // If not handling any auto-close operation, then just replace the selected
 4240            // text with the given input and move the selection to the end of the
 4241            // newly inserted text.
 4242            let anchor = snapshot.anchor_after(selection.end);
 4243            if !self.linked_edit_ranges.is_empty() {
 4244                let start_anchor = snapshot.anchor_before(selection.start);
 4245
 4246                let is_word_char = text.chars().next().is_none_or(|char| {
 4247                    let classifier = snapshot
 4248                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4249                        .ignore_punctuation(true);
 4250                    classifier.is_word(char)
 4251                });
 4252
 4253                if is_word_char {
 4254                    if let Some(ranges) = self
 4255                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4256                    {
 4257                        for (buffer, edits) in ranges {
 4258                            linked_edits
 4259                                .entry(buffer.clone())
 4260                                .or_default()
 4261                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4262                        }
 4263                    }
 4264                } else {
 4265                    clear_linked_edit_ranges = true;
 4266                }
 4267            }
 4268
 4269            new_selections.push((selection.map(|_| anchor), 0));
 4270            edits.push((selection.start..selection.end, text.clone()));
 4271        }
 4272
 4273        drop(snapshot);
 4274
 4275        self.transact(window, cx, |this, window, cx| {
 4276            if clear_linked_edit_ranges {
 4277                this.linked_edit_ranges.clear();
 4278            }
 4279            let initial_buffer_versions =
 4280                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4281
 4282            this.buffer.update(cx, |buffer, cx| {
 4283                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4284            });
 4285            for (buffer, edits) in linked_edits {
 4286                buffer.update(cx, |buffer, cx| {
 4287                    let snapshot = buffer.snapshot();
 4288                    let edits = edits
 4289                        .into_iter()
 4290                        .map(|(range, text)| {
 4291                            use text::ToPoint as TP;
 4292                            let end_point = TP::to_point(&range.end, &snapshot);
 4293                            let start_point = TP::to_point(&range.start, &snapshot);
 4294                            (start_point..end_point, text)
 4295                        })
 4296                        .sorted_by_key(|(range, _)| range.start);
 4297                    buffer.edit(edits, None, cx);
 4298                })
 4299            }
 4300            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4301            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4302            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4303            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4304                .zip(new_selection_deltas)
 4305                .map(|(selection, delta)| Selection {
 4306                    id: selection.id,
 4307                    start: selection.start + delta,
 4308                    end: selection.end + delta,
 4309                    reversed: selection.reversed,
 4310                    goal: SelectionGoal::None,
 4311                })
 4312                .collect::<Vec<_>>();
 4313
 4314            let mut i = 0;
 4315            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4316                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4317                let start = map.buffer_snapshot.anchor_before(position);
 4318                let end = map.buffer_snapshot.anchor_after(position);
 4319                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4320                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4321                        Ordering::Less => i += 1,
 4322                        Ordering::Greater => break,
 4323                        Ordering::Equal => {
 4324                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4325                                Ordering::Less => i += 1,
 4326                                Ordering::Equal => break,
 4327                                Ordering::Greater => break,
 4328                            }
 4329                        }
 4330                    }
 4331                }
 4332                this.autoclose_regions.insert(
 4333                    i,
 4334                    AutocloseRegion {
 4335                        selection_id,
 4336                        range: start..end,
 4337                        pair,
 4338                    },
 4339                );
 4340            }
 4341
 4342            let had_active_edit_prediction = this.has_active_edit_prediction();
 4343            this.change_selections(
 4344                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4345                window,
 4346                cx,
 4347                |s| s.select(new_selections),
 4348            );
 4349
 4350            if !bracket_inserted
 4351                && let Some(on_type_format_task) =
 4352                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4353            {
 4354                on_type_format_task.detach_and_log_err(cx);
 4355            }
 4356
 4357            let editor_settings = EditorSettings::get_global(cx);
 4358            if bracket_inserted
 4359                && (editor_settings.auto_signature_help
 4360                    || editor_settings.show_signature_help_after_edits)
 4361            {
 4362                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4363            }
 4364
 4365            let trigger_in_words =
 4366                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4367            if this.hard_wrap.is_some() {
 4368                let latest: Range<Point> = this.selections.newest(cx).range();
 4369                if latest.is_empty()
 4370                    && this
 4371                        .buffer()
 4372                        .read(cx)
 4373                        .snapshot(cx)
 4374                        .line_len(MultiBufferRow(latest.start.row))
 4375                        == latest.start.column
 4376                {
 4377                    this.rewrap_impl(
 4378                        RewrapOptions {
 4379                            override_language_settings: true,
 4380                            preserve_existing_whitespace: true,
 4381                        },
 4382                        cx,
 4383                    )
 4384                }
 4385            }
 4386            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4387            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4388            this.refresh_edit_prediction(true, false, window, cx);
 4389            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4390        });
 4391    }
 4392
 4393    fn find_possible_emoji_shortcode_at_position(
 4394        snapshot: &MultiBufferSnapshot,
 4395        position: Point,
 4396    ) -> Option<String> {
 4397        let mut chars = Vec::new();
 4398        let mut found_colon = false;
 4399        for char in snapshot.reversed_chars_at(position).take(100) {
 4400            // Found a possible emoji shortcode in the middle of the buffer
 4401            if found_colon {
 4402                if char.is_whitespace() {
 4403                    chars.reverse();
 4404                    return Some(chars.iter().collect());
 4405                }
 4406                // If the previous character is not a whitespace, we are in the middle of a word
 4407                // and we only want to complete the shortcode if the word is made up of other emojis
 4408                let mut containing_word = String::new();
 4409                for ch in snapshot
 4410                    .reversed_chars_at(position)
 4411                    .skip(chars.len() + 1)
 4412                    .take(100)
 4413                {
 4414                    if ch.is_whitespace() {
 4415                        break;
 4416                    }
 4417                    containing_word.push(ch);
 4418                }
 4419                let containing_word = containing_word.chars().rev().collect::<String>();
 4420                if util::word_consists_of_emojis(containing_word.as_str()) {
 4421                    chars.reverse();
 4422                    return Some(chars.iter().collect());
 4423                }
 4424            }
 4425
 4426            if char.is_whitespace() || !char.is_ascii() {
 4427                return None;
 4428            }
 4429            if char == ':' {
 4430                found_colon = true;
 4431            } else {
 4432                chars.push(char);
 4433            }
 4434        }
 4435        // Found a possible emoji shortcode at the beginning of the buffer
 4436        chars.reverse();
 4437        Some(chars.iter().collect())
 4438    }
 4439
 4440    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4441        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4442        self.transact(window, cx, |this, window, cx| {
 4443            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4444                let selections = this.selections.all::<usize>(cx);
 4445                let multi_buffer = this.buffer.read(cx);
 4446                let buffer = multi_buffer.snapshot(cx);
 4447                selections
 4448                    .iter()
 4449                    .map(|selection| {
 4450                        let start_point = selection.start.to_point(&buffer);
 4451                        let mut existing_indent =
 4452                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4453                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4454                        let start = selection.start;
 4455                        let end = selection.end;
 4456                        let selection_is_empty = start == end;
 4457                        let language_scope = buffer.language_scope_at(start);
 4458                        let (
 4459                            comment_delimiter,
 4460                            doc_delimiter,
 4461                            insert_extra_newline,
 4462                            indent_on_newline,
 4463                            indent_on_extra_newline,
 4464                        ) = if let Some(language) = &language_scope {
 4465                            let mut insert_extra_newline =
 4466                                insert_extra_newline_brackets(&buffer, start..end, language)
 4467                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4468
 4469                            // Comment extension on newline is allowed only for cursor selections
 4470                            let comment_delimiter = maybe!({
 4471                                if !selection_is_empty {
 4472                                    return None;
 4473                                }
 4474
 4475                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4476                                    return None;
 4477                                }
 4478
 4479                                let delimiters = language.line_comment_prefixes();
 4480                                let max_len_of_delimiter =
 4481                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4482                                let (snapshot, range) =
 4483                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4484
 4485                                let num_of_whitespaces = snapshot
 4486                                    .chars_for_range(range.clone())
 4487                                    .take_while(|c| c.is_whitespace())
 4488                                    .count();
 4489                                let comment_candidate = snapshot
 4490                                    .chars_for_range(range.clone())
 4491                                    .skip(num_of_whitespaces)
 4492                                    .take(max_len_of_delimiter)
 4493                                    .collect::<String>();
 4494                                let (delimiter, trimmed_len) = delimiters
 4495                                    .iter()
 4496                                    .filter_map(|delimiter| {
 4497                                        let prefix = delimiter.trim_end();
 4498                                        if comment_candidate.starts_with(prefix) {
 4499                                            Some((delimiter, prefix.len()))
 4500                                        } else {
 4501                                            None
 4502                                        }
 4503                                    })
 4504                                    .max_by_key(|(_, len)| *len)?;
 4505
 4506                                if let Some(BlockCommentConfig {
 4507                                    start: block_start, ..
 4508                                }) = language.block_comment()
 4509                                {
 4510                                    let block_start_trimmed = block_start.trim_end();
 4511                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4512                                        let line_content = snapshot
 4513                                            .chars_for_range(range)
 4514                                            .skip(num_of_whitespaces)
 4515                                            .take(block_start_trimmed.len())
 4516                                            .collect::<String>();
 4517
 4518                                        if line_content.starts_with(block_start_trimmed) {
 4519                                            return None;
 4520                                        }
 4521                                    }
 4522                                }
 4523
 4524                                let cursor_is_placed_after_comment_marker =
 4525                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4526                                if cursor_is_placed_after_comment_marker {
 4527                                    Some(delimiter.clone())
 4528                                } else {
 4529                                    None
 4530                                }
 4531                            });
 4532
 4533                            let mut indent_on_newline = IndentSize::spaces(0);
 4534                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4535
 4536                            let doc_delimiter = maybe!({
 4537                                if !selection_is_empty {
 4538                                    return None;
 4539                                }
 4540
 4541                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4542                                    return None;
 4543                                }
 4544
 4545                                let BlockCommentConfig {
 4546                                    start: start_tag,
 4547                                    end: end_tag,
 4548                                    prefix: delimiter,
 4549                                    tab_size: len,
 4550                                } = language.documentation_comment()?;
 4551                                let is_within_block_comment = buffer
 4552                                    .language_scope_at(start_point)
 4553                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4554                                if !is_within_block_comment {
 4555                                    return None;
 4556                                }
 4557
 4558                                let (snapshot, range) =
 4559                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4560
 4561                                let num_of_whitespaces = snapshot
 4562                                    .chars_for_range(range.clone())
 4563                                    .take_while(|c| c.is_whitespace())
 4564                                    .count();
 4565
 4566                                // 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.
 4567                                let column = start_point.column;
 4568                                let cursor_is_after_start_tag = {
 4569                                    let start_tag_len = start_tag.len();
 4570                                    let start_tag_line = snapshot
 4571                                        .chars_for_range(range.clone())
 4572                                        .skip(num_of_whitespaces)
 4573                                        .take(start_tag_len)
 4574                                        .collect::<String>();
 4575                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4576                                        num_of_whitespaces + start_tag_len <= column as usize
 4577                                    } else {
 4578                                        false
 4579                                    }
 4580                                };
 4581
 4582                                let cursor_is_after_delimiter = {
 4583                                    let delimiter_trim = delimiter.trim_end();
 4584                                    let delimiter_line = snapshot
 4585                                        .chars_for_range(range.clone())
 4586                                        .skip(num_of_whitespaces)
 4587                                        .take(delimiter_trim.len())
 4588                                        .collect::<String>();
 4589                                    if delimiter_line.starts_with(delimiter_trim) {
 4590                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4591                                    } else {
 4592                                        false
 4593                                    }
 4594                                };
 4595
 4596                                let cursor_is_before_end_tag_if_exists = {
 4597                                    let mut char_position = 0u32;
 4598                                    let mut end_tag_offset = None;
 4599
 4600                                    'outer: for chunk in snapshot.text_for_range(range) {
 4601                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4602                                            let chars_before_match =
 4603                                                chunk[..byte_pos].chars().count() as u32;
 4604                                            end_tag_offset =
 4605                                                Some(char_position + chars_before_match);
 4606                                            break 'outer;
 4607                                        }
 4608                                        char_position += chunk.chars().count() as u32;
 4609                                    }
 4610
 4611                                    if let Some(end_tag_offset) = end_tag_offset {
 4612                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4613                                        if cursor_is_after_start_tag {
 4614                                            if cursor_is_before_end_tag {
 4615                                                insert_extra_newline = true;
 4616                                            }
 4617                                            let cursor_is_at_start_of_end_tag =
 4618                                                column == end_tag_offset;
 4619                                            if cursor_is_at_start_of_end_tag {
 4620                                                indent_on_extra_newline.len = *len;
 4621                                            }
 4622                                        }
 4623                                        cursor_is_before_end_tag
 4624                                    } else {
 4625                                        true
 4626                                    }
 4627                                };
 4628
 4629                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4630                                    && cursor_is_before_end_tag_if_exists
 4631                                {
 4632                                    if cursor_is_after_start_tag {
 4633                                        indent_on_newline.len = *len;
 4634                                    }
 4635                                    Some(delimiter.clone())
 4636                                } else {
 4637                                    None
 4638                                }
 4639                            });
 4640
 4641                            (
 4642                                comment_delimiter,
 4643                                doc_delimiter,
 4644                                insert_extra_newline,
 4645                                indent_on_newline,
 4646                                indent_on_extra_newline,
 4647                            )
 4648                        } else {
 4649                            (
 4650                                None,
 4651                                None,
 4652                                false,
 4653                                IndentSize::default(),
 4654                                IndentSize::default(),
 4655                            )
 4656                        };
 4657
 4658                        let prevent_auto_indent = doc_delimiter.is_some();
 4659                        let delimiter = comment_delimiter.or(doc_delimiter);
 4660
 4661                        let capacity_for_delimiter =
 4662                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4663                        let mut new_text = String::with_capacity(
 4664                            1 + capacity_for_delimiter
 4665                                + existing_indent.len as usize
 4666                                + indent_on_newline.len as usize
 4667                                + indent_on_extra_newline.len as usize,
 4668                        );
 4669                        new_text.push('\n');
 4670                        new_text.extend(existing_indent.chars());
 4671                        new_text.extend(indent_on_newline.chars());
 4672
 4673                        if let Some(delimiter) = &delimiter {
 4674                            new_text.push_str(delimiter);
 4675                        }
 4676
 4677                        if insert_extra_newline {
 4678                            new_text.push('\n');
 4679                            new_text.extend(existing_indent.chars());
 4680                            new_text.extend(indent_on_extra_newline.chars());
 4681                        }
 4682
 4683                        let anchor = buffer.anchor_after(end);
 4684                        let new_selection = selection.map(|_| anchor);
 4685                        (
 4686                            ((start..end, new_text), prevent_auto_indent),
 4687                            (insert_extra_newline, new_selection),
 4688                        )
 4689                    })
 4690                    .unzip()
 4691            };
 4692
 4693            let mut auto_indent_edits = Vec::new();
 4694            let mut edits = Vec::new();
 4695            for (edit, prevent_auto_indent) in edits_with_flags {
 4696                if prevent_auto_indent {
 4697                    edits.push(edit);
 4698                } else {
 4699                    auto_indent_edits.push(edit);
 4700                }
 4701            }
 4702            if !edits.is_empty() {
 4703                this.edit(edits, cx);
 4704            }
 4705            if !auto_indent_edits.is_empty() {
 4706                this.edit_with_autoindent(auto_indent_edits, cx);
 4707            }
 4708
 4709            let buffer = this.buffer.read(cx).snapshot(cx);
 4710            let new_selections = selection_info
 4711                .into_iter()
 4712                .map(|(extra_newline_inserted, new_selection)| {
 4713                    let mut cursor = new_selection.end.to_point(&buffer);
 4714                    if extra_newline_inserted {
 4715                        cursor.row -= 1;
 4716                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4717                    }
 4718                    new_selection.map(|_| cursor)
 4719                })
 4720                .collect();
 4721
 4722            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4723            this.refresh_edit_prediction(true, false, window, cx);
 4724        });
 4725    }
 4726
 4727    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4729
 4730        let buffer = self.buffer.read(cx);
 4731        let snapshot = buffer.snapshot(cx);
 4732
 4733        let mut edits = Vec::new();
 4734        let mut rows = Vec::new();
 4735
 4736        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4737            let cursor = selection.head();
 4738            let row = cursor.row;
 4739
 4740            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4741
 4742            let newline = "\n".to_string();
 4743            edits.push((start_of_line..start_of_line, newline));
 4744
 4745            rows.push(row + rows_inserted as u32);
 4746        }
 4747
 4748        self.transact(window, cx, |editor, window, cx| {
 4749            editor.edit(edits, cx);
 4750
 4751            editor.change_selections(Default::default(), window, cx, |s| {
 4752                let mut index = 0;
 4753                s.move_cursors_with(|map, _, _| {
 4754                    let row = rows[index];
 4755                    index += 1;
 4756
 4757                    let point = Point::new(row, 0);
 4758                    let boundary = map.next_line_boundary(point).1;
 4759                    let clipped = map.clip_point(boundary, Bias::Left);
 4760
 4761                    (clipped, SelectionGoal::None)
 4762                });
 4763            });
 4764
 4765            let mut indent_edits = Vec::new();
 4766            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4767            for row in rows {
 4768                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4769                for (row, indent) in indents {
 4770                    if indent.len == 0 {
 4771                        continue;
 4772                    }
 4773
 4774                    let text = match indent.kind {
 4775                        IndentKind::Space => " ".repeat(indent.len as usize),
 4776                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4777                    };
 4778                    let point = Point::new(row.0, 0);
 4779                    indent_edits.push((point..point, text));
 4780                }
 4781            }
 4782            editor.edit(indent_edits, cx);
 4783        });
 4784    }
 4785
 4786    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4787        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4788
 4789        let buffer = self.buffer.read(cx);
 4790        let snapshot = buffer.snapshot(cx);
 4791
 4792        let mut edits = Vec::new();
 4793        let mut rows = Vec::new();
 4794        let mut rows_inserted = 0;
 4795
 4796        for selection in self.selections.all_adjusted(cx) {
 4797            let cursor = selection.head();
 4798            let row = cursor.row;
 4799
 4800            let point = Point::new(row + 1, 0);
 4801            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4802
 4803            let newline = "\n".to_string();
 4804            edits.push((start_of_line..start_of_line, newline));
 4805
 4806            rows_inserted += 1;
 4807            rows.push(row + rows_inserted);
 4808        }
 4809
 4810        self.transact(window, cx, |editor, window, cx| {
 4811            editor.edit(edits, cx);
 4812
 4813            editor.change_selections(Default::default(), window, cx, |s| {
 4814                let mut index = 0;
 4815                s.move_cursors_with(|map, _, _| {
 4816                    let row = rows[index];
 4817                    index += 1;
 4818
 4819                    let point = Point::new(row, 0);
 4820                    let boundary = map.next_line_boundary(point).1;
 4821                    let clipped = map.clip_point(boundary, Bias::Left);
 4822
 4823                    (clipped, SelectionGoal::None)
 4824                });
 4825            });
 4826
 4827            let mut indent_edits = Vec::new();
 4828            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4829            for row in rows {
 4830                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4831                for (row, indent) in indents {
 4832                    if indent.len == 0 {
 4833                        continue;
 4834                    }
 4835
 4836                    let text = match indent.kind {
 4837                        IndentKind::Space => " ".repeat(indent.len as usize),
 4838                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4839                    };
 4840                    let point = Point::new(row.0, 0);
 4841                    indent_edits.push((point..point, text));
 4842                }
 4843            }
 4844            editor.edit(indent_edits, cx);
 4845        });
 4846    }
 4847
 4848    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4849        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4850            original_indent_columns: Vec::new(),
 4851        });
 4852        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4853    }
 4854
 4855    fn insert_with_autoindent_mode(
 4856        &mut self,
 4857        text: &str,
 4858        autoindent_mode: Option<AutoindentMode>,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        if self.read_only(cx) {
 4863            return;
 4864        }
 4865
 4866        let text: Arc<str> = text.into();
 4867        self.transact(window, cx, |this, window, cx| {
 4868            let old_selections = this.selections.all_adjusted(cx);
 4869            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4870                let anchors = {
 4871                    let snapshot = buffer.read(cx);
 4872                    old_selections
 4873                        .iter()
 4874                        .map(|s| {
 4875                            let anchor = snapshot.anchor_after(s.head());
 4876                            s.map(|_| anchor)
 4877                        })
 4878                        .collect::<Vec<_>>()
 4879                };
 4880                buffer.edit(
 4881                    old_selections
 4882                        .iter()
 4883                        .map(|s| (s.start..s.end, text.clone())),
 4884                    autoindent_mode,
 4885                    cx,
 4886                );
 4887                anchors
 4888            });
 4889
 4890            this.change_selections(Default::default(), window, cx, |s| {
 4891                s.select_anchors(selection_anchors);
 4892            });
 4893
 4894            cx.notify();
 4895        });
 4896    }
 4897
 4898    fn trigger_completion_on_input(
 4899        &mut self,
 4900        text: &str,
 4901        trigger_in_words: bool,
 4902        window: &mut Window,
 4903        cx: &mut Context<Self>,
 4904    ) {
 4905        let completions_source = self
 4906            .context_menu
 4907            .borrow()
 4908            .as_ref()
 4909            .and_then(|menu| match menu {
 4910                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4911                CodeContextMenu::CodeActions(_) => None,
 4912            });
 4913
 4914        match completions_source {
 4915            Some(CompletionsMenuSource::Words { .. }) => {
 4916                self.open_or_update_completions_menu(
 4917                    Some(CompletionsMenuSource::Words {
 4918                        ignore_threshold: false,
 4919                    }),
 4920                    None,
 4921                    window,
 4922                    cx,
 4923                );
 4924            }
 4925            Some(CompletionsMenuSource::Normal)
 4926            | Some(CompletionsMenuSource::SnippetChoices)
 4927            | None
 4928                if self.is_completion_trigger(
 4929                    text,
 4930                    trigger_in_words,
 4931                    completions_source.is_some(),
 4932                    cx,
 4933                ) =>
 4934            {
 4935                self.show_completions(
 4936                    &ShowCompletions {
 4937                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4938                    },
 4939                    window,
 4940                    cx,
 4941                )
 4942            }
 4943            _ => {
 4944                self.hide_context_menu(window, cx);
 4945            }
 4946        }
 4947    }
 4948
 4949    fn is_completion_trigger(
 4950        &self,
 4951        text: &str,
 4952        trigger_in_words: bool,
 4953        menu_is_open: bool,
 4954        cx: &mut Context<Self>,
 4955    ) -> bool {
 4956        let position = self.selections.newest_anchor().head();
 4957        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4958            return false;
 4959        };
 4960
 4961        if let Some(completion_provider) = &self.completion_provider {
 4962            completion_provider.is_completion_trigger(
 4963                &buffer,
 4964                position.text_anchor,
 4965                text,
 4966                trigger_in_words,
 4967                menu_is_open,
 4968                cx,
 4969            )
 4970        } else {
 4971            false
 4972        }
 4973    }
 4974
 4975    /// If any empty selections is touching the start of its innermost containing autoclose
 4976    /// region, expand it to select the brackets.
 4977    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4978        let selections = self.selections.all::<usize>(cx);
 4979        let buffer = self.buffer.read(cx).read(cx);
 4980        let new_selections = self
 4981            .selections_with_autoclose_regions(selections, &buffer)
 4982            .map(|(mut selection, region)| {
 4983                if !selection.is_empty() {
 4984                    return selection;
 4985                }
 4986
 4987                if let Some(region) = region {
 4988                    let mut range = region.range.to_offset(&buffer);
 4989                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4990                        range.start -= region.pair.start.len();
 4991                        if buffer.contains_str_at(range.start, &region.pair.start)
 4992                            && buffer.contains_str_at(range.end, &region.pair.end)
 4993                        {
 4994                            range.end += region.pair.end.len();
 4995                            selection.start = range.start;
 4996                            selection.end = range.end;
 4997
 4998                            return selection;
 4999                        }
 5000                    }
 5001                }
 5002
 5003                let always_treat_brackets_as_autoclosed = buffer
 5004                    .language_settings_at(selection.start, cx)
 5005                    .always_treat_brackets_as_autoclosed;
 5006
 5007                if !always_treat_brackets_as_autoclosed {
 5008                    return selection;
 5009                }
 5010
 5011                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5012                    for (pair, enabled) in scope.brackets() {
 5013                        if !enabled || !pair.close {
 5014                            continue;
 5015                        }
 5016
 5017                        if buffer.contains_str_at(selection.start, &pair.end) {
 5018                            let pair_start_len = pair.start.len();
 5019                            if buffer.contains_str_at(
 5020                                selection.start.saturating_sub(pair_start_len),
 5021                                &pair.start,
 5022                            ) {
 5023                                selection.start -= pair_start_len;
 5024                                selection.end += pair.end.len();
 5025
 5026                                return selection;
 5027                            }
 5028                        }
 5029                    }
 5030                }
 5031
 5032                selection
 5033            })
 5034            .collect();
 5035
 5036        drop(buffer);
 5037        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5038            selections.select(new_selections)
 5039        });
 5040    }
 5041
 5042    /// Iterate the given selections, and for each one, find the smallest surrounding
 5043    /// autoclose region. This uses the ordering of the selections and the autoclose
 5044    /// regions to avoid repeated comparisons.
 5045    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5046        &'a self,
 5047        selections: impl IntoIterator<Item = Selection<D>>,
 5048        buffer: &'a MultiBufferSnapshot,
 5049    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5050        let mut i = 0;
 5051        let mut regions = self.autoclose_regions.as_slice();
 5052        selections.into_iter().map(move |selection| {
 5053            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5054
 5055            let mut enclosing = None;
 5056            while let Some(pair_state) = regions.get(i) {
 5057                if pair_state.range.end.to_offset(buffer) < range.start {
 5058                    regions = &regions[i + 1..];
 5059                    i = 0;
 5060                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5061                    break;
 5062                } else {
 5063                    if pair_state.selection_id == selection.id {
 5064                        enclosing = Some(pair_state);
 5065                    }
 5066                    i += 1;
 5067                }
 5068            }
 5069
 5070            (selection, enclosing)
 5071        })
 5072    }
 5073
 5074    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5075    fn invalidate_autoclose_regions(
 5076        &mut self,
 5077        mut selections: &[Selection<Anchor>],
 5078        buffer: &MultiBufferSnapshot,
 5079    ) {
 5080        self.autoclose_regions.retain(|state| {
 5081            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5082                return false;
 5083            }
 5084
 5085            let mut i = 0;
 5086            while let Some(selection) = selections.get(i) {
 5087                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5088                    selections = &selections[1..];
 5089                    continue;
 5090                }
 5091                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5092                    break;
 5093                }
 5094                if selection.id == state.selection_id {
 5095                    return true;
 5096                } else {
 5097                    i += 1;
 5098                }
 5099            }
 5100            false
 5101        });
 5102    }
 5103
 5104    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5105        let offset = position.to_offset(buffer);
 5106        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5107        if offset > word_range.start && kind == Some(CharKind::Word) {
 5108            Some(
 5109                buffer
 5110                    .text_for_range(word_range.start..offset)
 5111                    .collect::<String>(),
 5112            )
 5113        } else {
 5114            None
 5115        }
 5116    }
 5117
 5118    pub fn toggle_inline_values(
 5119        &mut self,
 5120        _: &ToggleInlineValues,
 5121        _: &mut Window,
 5122        cx: &mut Context<Self>,
 5123    ) {
 5124        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5125
 5126        self.refresh_inline_values(cx);
 5127    }
 5128
 5129    pub fn toggle_inlay_hints(
 5130        &mut self,
 5131        _: &ToggleInlayHints,
 5132        _: &mut Window,
 5133        cx: &mut Context<Self>,
 5134    ) {
 5135        self.refresh_inlay_hints(
 5136            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5137            cx,
 5138        );
 5139    }
 5140
 5141    pub fn inlay_hints_enabled(&self) -> bool {
 5142        self.inlay_hint_cache.enabled
 5143    }
 5144
 5145    pub fn inline_values_enabled(&self) -> bool {
 5146        self.inline_value_cache.enabled
 5147    }
 5148
 5149    #[cfg(any(test, feature = "test-support"))]
 5150    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5151        self.display_map
 5152            .read(cx)
 5153            .current_inlays()
 5154            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5155            .cloned()
 5156            .collect()
 5157    }
 5158
 5159    #[cfg(any(test, feature = "test-support"))]
 5160    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5161        self.display_map
 5162            .read(cx)
 5163            .current_inlays()
 5164            .cloned()
 5165            .collect()
 5166    }
 5167
 5168    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5169        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5170            return;
 5171        }
 5172
 5173        let reason_description = reason.description();
 5174        let ignore_debounce = matches!(
 5175            reason,
 5176            InlayHintRefreshReason::SettingsChange(_)
 5177                | InlayHintRefreshReason::Toggle(_)
 5178                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5179                | InlayHintRefreshReason::ModifiersChanged(_)
 5180        );
 5181        let (invalidate_cache, required_languages) = match reason {
 5182            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5183                match self.inlay_hint_cache.modifiers_override(enabled) {
 5184                    Some(enabled) => {
 5185                        if enabled {
 5186                            (InvalidationStrategy::RefreshRequested, None)
 5187                        } else {
 5188                            self.splice_inlays(
 5189                                &self
 5190                                    .visible_inlay_hints(cx)
 5191                                    .iter()
 5192                                    .map(|inlay| inlay.id)
 5193                                    .collect::<Vec<InlayId>>(),
 5194                                Vec::new(),
 5195                                cx,
 5196                            );
 5197                            return;
 5198                        }
 5199                    }
 5200                    None => return,
 5201                }
 5202            }
 5203            InlayHintRefreshReason::Toggle(enabled) => {
 5204                if self.inlay_hint_cache.toggle(enabled) {
 5205                    if enabled {
 5206                        (InvalidationStrategy::RefreshRequested, None)
 5207                    } else {
 5208                        self.splice_inlays(
 5209                            &self
 5210                                .visible_inlay_hints(cx)
 5211                                .iter()
 5212                                .map(|inlay| inlay.id)
 5213                                .collect::<Vec<InlayId>>(),
 5214                            Vec::new(),
 5215                            cx,
 5216                        );
 5217                        return;
 5218                    }
 5219                } else {
 5220                    return;
 5221                }
 5222            }
 5223            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5224                match self.inlay_hint_cache.update_settings(
 5225                    &self.buffer,
 5226                    new_settings,
 5227                    self.visible_inlay_hints(cx),
 5228                    cx,
 5229                ) {
 5230                    ControlFlow::Break(Some(InlaySplice {
 5231                        to_remove,
 5232                        to_insert,
 5233                    })) => {
 5234                        self.splice_inlays(&to_remove, to_insert, cx);
 5235                        return;
 5236                    }
 5237                    ControlFlow::Break(None) => return,
 5238                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5239                }
 5240            }
 5241            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5242                if let Some(InlaySplice {
 5243                    to_remove,
 5244                    to_insert,
 5245                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5246                {
 5247                    self.splice_inlays(&to_remove, to_insert, cx);
 5248                }
 5249                self.display_map.update(cx, |display_map, _| {
 5250                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5251                });
 5252                return;
 5253            }
 5254            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5255            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5256                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5257            }
 5258            InlayHintRefreshReason::RefreshRequested => {
 5259                (InvalidationStrategy::RefreshRequested, None)
 5260            }
 5261        };
 5262
 5263        if let Some(InlaySplice {
 5264            to_remove,
 5265            to_insert,
 5266        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5267            reason_description,
 5268            self.visible_excerpts(required_languages.as_ref(), cx),
 5269            invalidate_cache,
 5270            ignore_debounce,
 5271            cx,
 5272        ) {
 5273            self.splice_inlays(&to_remove, to_insert, cx);
 5274        }
 5275    }
 5276
 5277    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5278        self.display_map
 5279            .read(cx)
 5280            .current_inlays()
 5281            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5282            .cloned()
 5283            .collect()
 5284    }
 5285
 5286    pub fn visible_excerpts(
 5287        &self,
 5288        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5289        cx: &mut Context<Editor>,
 5290    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5291        let Some(project) = self.project() else {
 5292            return HashMap::default();
 5293        };
 5294        let project = project.read(cx);
 5295        let multi_buffer = self.buffer().read(cx);
 5296        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5297        let multi_buffer_visible_start = self
 5298            .scroll_manager
 5299            .anchor()
 5300            .anchor
 5301            .to_point(&multi_buffer_snapshot);
 5302        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5303            multi_buffer_visible_start
 5304                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5305            Bias::Left,
 5306        );
 5307        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5308        multi_buffer_snapshot
 5309            .range_to_buffer_ranges(multi_buffer_visible_range)
 5310            .into_iter()
 5311            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5312            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5313                let buffer_file = project::File::from_dyn(buffer.file())?;
 5314                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5315                let worktree_entry = buffer_worktree
 5316                    .read(cx)
 5317                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5318                if worktree_entry.is_ignored {
 5319                    return None;
 5320                }
 5321
 5322                let language = buffer.language()?;
 5323                if let Some(restrict_to_languages) = restrict_to_languages
 5324                    && !restrict_to_languages.contains(language)
 5325                {
 5326                    return None;
 5327                }
 5328                Some((
 5329                    excerpt_id,
 5330                    (
 5331                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5332                        buffer.version().clone(),
 5333                        excerpt_visible_range,
 5334                    ),
 5335                ))
 5336            })
 5337            .collect()
 5338    }
 5339
 5340    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5341        TextLayoutDetails {
 5342            text_system: window.text_system().clone(),
 5343            editor_style: self.style.clone().unwrap(),
 5344            rem_size: window.rem_size(),
 5345            scroll_anchor: self.scroll_manager.anchor(),
 5346            visible_rows: self.visible_line_count(),
 5347            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5348        }
 5349    }
 5350
 5351    pub fn splice_inlays(
 5352        &self,
 5353        to_remove: &[InlayId],
 5354        to_insert: Vec<Inlay>,
 5355        cx: &mut Context<Self>,
 5356    ) {
 5357        self.display_map.update(cx, |display_map, cx| {
 5358            display_map.splice_inlays(to_remove, to_insert, cx)
 5359        });
 5360        cx.notify();
 5361    }
 5362
 5363    fn trigger_on_type_formatting(
 5364        &self,
 5365        input: String,
 5366        window: &mut Window,
 5367        cx: &mut Context<Self>,
 5368    ) -> Option<Task<Result<()>>> {
 5369        if input.len() != 1 {
 5370            return None;
 5371        }
 5372
 5373        let project = self.project()?;
 5374        let position = self.selections.newest_anchor().head();
 5375        let (buffer, buffer_position) = self
 5376            .buffer
 5377            .read(cx)
 5378            .text_anchor_for_position(position, cx)?;
 5379
 5380        let settings = language_settings::language_settings(
 5381            buffer
 5382                .read(cx)
 5383                .language_at(buffer_position)
 5384                .map(|l| l.name()),
 5385            buffer.read(cx).file(),
 5386            cx,
 5387        );
 5388        if !settings.use_on_type_format {
 5389            return None;
 5390        }
 5391
 5392        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5393        // hence we do LSP request & edit on host side only — add formats to host's history.
 5394        let push_to_lsp_host_history = true;
 5395        // If this is not the host, append its history with new edits.
 5396        let push_to_client_history = project.read(cx).is_via_collab();
 5397
 5398        let on_type_formatting = project.update(cx, |project, cx| {
 5399            project.on_type_format(
 5400                buffer.clone(),
 5401                buffer_position,
 5402                input,
 5403                push_to_lsp_host_history,
 5404                cx,
 5405            )
 5406        });
 5407        Some(cx.spawn_in(window, async move |editor, cx| {
 5408            if let Some(transaction) = on_type_formatting.await? {
 5409                if push_to_client_history {
 5410                    buffer
 5411                        .update(cx, |buffer, _| {
 5412                            buffer.push_transaction(transaction, Instant::now());
 5413                            buffer.finalize_last_transaction();
 5414                        })
 5415                        .ok();
 5416                }
 5417                editor.update(cx, |editor, cx| {
 5418                    editor.refresh_document_highlights(cx);
 5419                })?;
 5420            }
 5421            Ok(())
 5422        }))
 5423    }
 5424
 5425    pub fn show_word_completions(
 5426        &mut self,
 5427        _: &ShowWordCompletions,
 5428        window: &mut Window,
 5429        cx: &mut Context<Self>,
 5430    ) {
 5431        self.open_or_update_completions_menu(
 5432            Some(CompletionsMenuSource::Words {
 5433                ignore_threshold: true,
 5434            }),
 5435            None,
 5436            window,
 5437            cx,
 5438        );
 5439    }
 5440
 5441    pub fn show_completions(
 5442        &mut self,
 5443        options: &ShowCompletions,
 5444        window: &mut Window,
 5445        cx: &mut Context<Self>,
 5446    ) {
 5447        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5448    }
 5449
 5450    fn open_or_update_completions_menu(
 5451        &mut self,
 5452        requested_source: Option<CompletionsMenuSource>,
 5453        trigger: Option<&str>,
 5454        window: &mut Window,
 5455        cx: &mut Context<Self>,
 5456    ) {
 5457        if self.pending_rename.is_some() {
 5458            return;
 5459        }
 5460
 5461        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5462
 5463        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5464        // inserted and selected. To handle that case, the start of the selection is used so that
 5465        // the menu starts with all choices.
 5466        let position = self
 5467            .selections
 5468            .newest_anchor()
 5469            .start
 5470            .bias_right(&multibuffer_snapshot);
 5471        if position.diff_base_anchor.is_some() {
 5472            return;
 5473        }
 5474        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5475        let Some(buffer) = buffer_position
 5476            .buffer_id
 5477            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5478        else {
 5479            return;
 5480        };
 5481        let buffer_snapshot = buffer.read(cx).snapshot();
 5482
 5483        let query: Option<Arc<String>> =
 5484            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5485                .map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        // Hide the current completions menu when query is empty. Without this, cached
 5490        // completions from before the trigger char may be reused (#32774).
 5491        if query.is_none() {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        let mut ignore_word_threshold = false;
 5502        let provider = match requested_source {
 5503            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5504            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5505                ignore_word_threshold = ignore_threshold;
 5506                None
 5507            }
 5508            Some(CompletionsMenuSource::SnippetChoices) => {
 5509                log::error!("bug: SnippetChoices requested_source is not handled");
 5510                None
 5511            }
 5512        };
 5513
 5514        let sort_completions = provider
 5515            .as_ref()
 5516            .is_some_and(|provider| provider.sort_completions());
 5517
 5518        let filter_completions = provider
 5519            .as_ref()
 5520            .is_none_or(|provider| provider.filter_completions());
 5521
 5522        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5523            if filter_completions {
 5524                menu.filter(query.clone(), provider.clone(), window, cx);
 5525            }
 5526            // When `is_incomplete` is false, no need to re-query completions when the current query
 5527            // is a suffix of the initial query.
 5528            if !menu.is_incomplete {
 5529                // If the new query is a suffix of the old query (typing more characters) and
 5530                // the previous result was complete, the existing completions can be filtered.
 5531                //
 5532                // Note that this is always true for snippet completions.
 5533                let query_matches = match (&menu.initial_query, &query) {
 5534                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5535                    (None, _) => true,
 5536                    _ => false,
 5537                };
 5538                if query_matches {
 5539                    let position_matches = if menu.initial_position == position {
 5540                        true
 5541                    } else {
 5542                        let snapshot = self.buffer.read(cx).read(cx);
 5543                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5544                    };
 5545                    if position_matches {
 5546                        return;
 5547                    }
 5548                }
 5549            }
 5550        };
 5551
 5552        let trigger_kind = match trigger {
 5553            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5554                CompletionTriggerKind::TRIGGER_CHARACTER
 5555            }
 5556            _ => CompletionTriggerKind::INVOKED,
 5557        };
 5558        let completion_context = CompletionContext {
 5559            trigger_character: trigger.and_then(|trigger| {
 5560                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5561                    Some(String::from(trigger))
 5562                } else {
 5563                    None
 5564                }
 5565            }),
 5566            trigger_kind,
 5567        };
 5568
 5569        let Anchor {
 5570            excerpt_id: buffer_excerpt_id,
 5571            text_anchor: buffer_position,
 5572            ..
 5573        } = buffer_position;
 5574
 5575        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5576            buffer_snapshot.surrounding_word(buffer_position, false)
 5577        {
 5578            let word_to_exclude = buffer_snapshot
 5579                .text_for_range(word_range.clone())
 5580                .collect::<String>();
 5581            (
 5582                buffer_snapshot.anchor_before(word_range.start)
 5583                    ..buffer_snapshot.anchor_after(buffer_position),
 5584                Some(word_to_exclude),
 5585            )
 5586        } else {
 5587            (buffer_position..buffer_position, None)
 5588        };
 5589
 5590        let language = buffer_snapshot
 5591            .language_at(buffer_position)
 5592            .map(|language| language.name());
 5593
 5594        let completion_settings =
 5595            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5596
 5597        let show_completion_documentation = buffer_snapshot
 5598            .settings_at(buffer_position, cx)
 5599            .show_completion_documentation;
 5600
 5601        // The document can be large, so stay in reasonable bounds when searching for words,
 5602        // otherwise completion pop-up might be slow to appear.
 5603        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5604        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5605        let min_word_search = buffer_snapshot.clip_point(
 5606            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5607            Bias::Left,
 5608        );
 5609        let max_word_search = buffer_snapshot.clip_point(
 5610            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5611            Bias::Right,
 5612        );
 5613        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5614            ..buffer_snapshot.point_to_offset(max_word_search);
 5615
 5616        let skip_digits = query
 5617            .as_ref()
 5618            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5619
 5620        let omit_word_completions = !self.word_completions_enabled
 5621            || (!ignore_word_threshold
 5622                && match &query {
 5623                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5624                    None => completion_settings.words_min_length != 0,
 5625                });
 5626
 5627        let (mut words, provider_responses) = match &provider {
 5628            Some(provider) => {
 5629                let provider_responses = provider.completions(
 5630                    buffer_excerpt_id,
 5631                    &buffer,
 5632                    buffer_position,
 5633                    completion_context,
 5634                    window,
 5635                    cx,
 5636                );
 5637
 5638                let words = match (omit_word_completions, completion_settings.words) {
 5639                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5640                        Task::ready(BTreeMap::default())
 5641                    }
 5642                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5643                        .background_spawn(async move {
 5644                            buffer_snapshot.words_in_range(WordsQuery {
 5645                                fuzzy_contents: None,
 5646                                range: word_search_range,
 5647                                skip_digits,
 5648                            })
 5649                        }),
 5650                };
 5651
 5652                (words, provider_responses)
 5653            }
 5654            None => {
 5655                let words = if omit_word_completions {
 5656                    Task::ready(BTreeMap::default())
 5657                } else {
 5658                    cx.background_spawn(async move {
 5659                        buffer_snapshot.words_in_range(WordsQuery {
 5660                            fuzzy_contents: None,
 5661                            range: word_search_range,
 5662                            skip_digits,
 5663                        })
 5664                    })
 5665                };
 5666                (words, Task::ready(Ok(Vec::new())))
 5667            }
 5668        };
 5669
 5670        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5671
 5672        let id = post_inc(&mut self.next_completion_id);
 5673        let task = cx.spawn_in(window, async move |editor, cx| {
 5674            let Ok(()) = editor.update(cx, |this, _| {
 5675                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5676            }) else {
 5677                return;
 5678            };
 5679
 5680            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5681            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5682            let mut completions = Vec::new();
 5683            let mut is_incomplete = false;
 5684            let mut display_options: Option<CompletionDisplayOptions> = None;
 5685            if let Some(provider_responses) = provider_responses.await.log_err()
 5686                && !provider_responses.is_empty()
 5687            {
 5688                for response in provider_responses {
 5689                    completions.extend(response.completions);
 5690                    is_incomplete = is_incomplete || response.is_incomplete;
 5691                    match display_options.as_mut() {
 5692                        None => {
 5693                            display_options = Some(response.display_options);
 5694                        }
 5695                        Some(options) => options.merge(&response.display_options),
 5696                    }
 5697                }
 5698                if completion_settings.words == WordsCompletionMode::Fallback {
 5699                    words = Task::ready(BTreeMap::default());
 5700                }
 5701            }
 5702            let display_options = display_options.unwrap_or_default();
 5703
 5704            let mut words = words.await;
 5705            if let Some(word_to_exclude) = &word_to_exclude {
 5706                words.remove(word_to_exclude);
 5707            }
 5708            for lsp_completion in &completions {
 5709                words.remove(&lsp_completion.new_text);
 5710            }
 5711            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5712                replace_range: word_replace_range.clone(),
 5713                new_text: word.clone(),
 5714                label: CodeLabel::plain(word, None),
 5715                icon_path: None,
 5716                documentation: None,
 5717                source: CompletionSource::BufferWord {
 5718                    word_range,
 5719                    resolved: false,
 5720                },
 5721                insert_text_mode: Some(InsertTextMode::AS_IS),
 5722                confirm: None,
 5723            }));
 5724
 5725            let menu = if completions.is_empty() {
 5726                None
 5727            } else {
 5728                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5729                    let languages = editor
 5730                        .workspace
 5731                        .as_ref()
 5732                        .and_then(|(workspace, _)| workspace.upgrade())
 5733                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5734                    let menu = CompletionsMenu::new(
 5735                        id,
 5736                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5737                        sort_completions,
 5738                        show_completion_documentation,
 5739                        position,
 5740                        query.clone(),
 5741                        is_incomplete,
 5742                        buffer.clone(),
 5743                        completions.into(),
 5744                        display_options,
 5745                        snippet_sort_order,
 5746                        languages,
 5747                        language,
 5748                        cx,
 5749                    );
 5750
 5751                    let query = if filter_completions { query } else { None };
 5752                    let matches_task = if let Some(query) = query {
 5753                        menu.do_async_filtering(query, cx)
 5754                    } else {
 5755                        Task::ready(menu.unfiltered_matches())
 5756                    };
 5757                    (menu, matches_task)
 5758                }) else {
 5759                    return;
 5760                };
 5761
 5762                let matches = matches_task.await;
 5763
 5764                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5765                    // Newer menu already set, so exit.
 5766                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5767                        editor.context_menu.borrow().as_ref()
 5768                        && prev_menu.id > id
 5769                    {
 5770                        return;
 5771                    };
 5772
 5773                    // Only valid to take prev_menu because it the new menu is immediately set
 5774                    // below, or the menu is hidden.
 5775                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5776                        editor.context_menu.borrow_mut().take()
 5777                    {
 5778                        let position_matches =
 5779                            if prev_menu.initial_position == menu.initial_position {
 5780                                true
 5781                            } else {
 5782                                let snapshot = editor.buffer.read(cx).read(cx);
 5783                                prev_menu.initial_position.to_offset(&snapshot)
 5784                                    == menu.initial_position.to_offset(&snapshot)
 5785                            };
 5786                        if position_matches {
 5787                            // Preserve markdown cache before `set_filter_results` because it will
 5788                            // try to populate the documentation cache.
 5789                            menu.preserve_markdown_cache(prev_menu);
 5790                        }
 5791                    };
 5792
 5793                    menu.set_filter_results(matches, provider, window, cx);
 5794                }) else {
 5795                    return;
 5796                };
 5797
 5798                menu.visible().then_some(menu)
 5799            };
 5800
 5801            editor
 5802                .update_in(cx, |editor, window, cx| {
 5803                    if editor.focus_handle.is_focused(window)
 5804                        && let Some(menu) = menu
 5805                    {
 5806                        *editor.context_menu.borrow_mut() =
 5807                            Some(CodeContextMenu::Completions(menu));
 5808
 5809                        crate::hover_popover::hide_hover(editor, cx);
 5810                        if editor.show_edit_predictions_in_menu() {
 5811                            editor.update_visible_edit_prediction(window, cx);
 5812                        } else {
 5813                            editor.discard_edit_prediction(false, cx);
 5814                        }
 5815
 5816                        cx.notify();
 5817                        return;
 5818                    }
 5819
 5820                    if editor.completion_tasks.len() <= 1 {
 5821                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5822                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5823                        // If it was already hidden and we don't show edit predictions in the menu,
 5824                        // we should also show the edit prediction when available.
 5825                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5826                            editor.update_visible_edit_prediction(window, cx);
 5827                        }
 5828                    }
 5829                })
 5830                .ok();
 5831        });
 5832
 5833        self.completion_tasks.push((id, task));
 5834    }
 5835
 5836    #[cfg(feature = "test-support")]
 5837    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5838        let menu = self.context_menu.borrow();
 5839        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5840            let completions = menu.completions.borrow();
 5841            Some(completions.to_vec())
 5842        } else {
 5843            None
 5844        }
 5845    }
 5846
 5847    pub fn with_completions_menu_matching_id<R>(
 5848        &self,
 5849        id: CompletionId,
 5850        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5851    ) -> R {
 5852        let mut context_menu = self.context_menu.borrow_mut();
 5853        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5854            return f(None);
 5855        };
 5856        if completions_menu.id != id {
 5857            return f(None);
 5858        }
 5859        f(Some(completions_menu))
 5860    }
 5861
 5862    pub fn confirm_completion(
 5863        &mut self,
 5864        action: &ConfirmCompletion,
 5865        window: &mut Window,
 5866        cx: &mut Context<Self>,
 5867    ) -> Option<Task<Result<()>>> {
 5868        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5869        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5870    }
 5871
 5872    pub fn confirm_completion_insert(
 5873        &mut self,
 5874        _: &ConfirmCompletionInsert,
 5875        window: &mut Window,
 5876        cx: &mut Context<Self>,
 5877    ) -> Option<Task<Result<()>>> {
 5878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5879        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5880    }
 5881
 5882    pub fn confirm_completion_replace(
 5883        &mut self,
 5884        _: &ConfirmCompletionReplace,
 5885        window: &mut Window,
 5886        cx: &mut Context<Self>,
 5887    ) -> Option<Task<Result<()>>> {
 5888        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5889        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5890    }
 5891
 5892    pub fn compose_completion(
 5893        &mut self,
 5894        action: &ComposeCompletion,
 5895        window: &mut Window,
 5896        cx: &mut Context<Self>,
 5897    ) -> Option<Task<Result<()>>> {
 5898        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5899        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5900    }
 5901
 5902    fn do_completion(
 5903        &mut self,
 5904        item_ix: Option<usize>,
 5905        intent: CompletionIntent,
 5906        window: &mut Window,
 5907        cx: &mut Context<Editor>,
 5908    ) -> Option<Task<Result<()>>> {
 5909        use language::ToOffset as _;
 5910
 5911        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5912        else {
 5913            return None;
 5914        };
 5915
 5916        let candidate_id = {
 5917            let entries = completions_menu.entries.borrow();
 5918            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5919            if self.show_edit_predictions_in_menu() {
 5920                self.discard_edit_prediction(true, cx);
 5921            }
 5922            mat.candidate_id
 5923        };
 5924
 5925        let completion = completions_menu
 5926            .completions
 5927            .borrow()
 5928            .get(candidate_id)?
 5929            .clone();
 5930        cx.stop_propagation();
 5931
 5932        let buffer_handle = completions_menu.buffer.clone();
 5933
 5934        let CompletionEdit {
 5935            new_text,
 5936            snippet,
 5937            replace_range,
 5938        } = process_completion_for_edit(
 5939            &completion,
 5940            intent,
 5941            &buffer_handle,
 5942            &completions_menu.initial_position.text_anchor,
 5943            cx,
 5944        );
 5945
 5946        let buffer = buffer_handle.read(cx);
 5947        let snapshot = self.buffer.read(cx).snapshot(cx);
 5948        let newest_anchor = self.selections.newest_anchor();
 5949        let replace_range_multibuffer = {
 5950            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5951            let multibuffer_anchor = snapshot
 5952                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5953                .unwrap()
 5954                ..snapshot
 5955                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5956                    .unwrap();
 5957            multibuffer_anchor.start.to_offset(&snapshot)
 5958                ..multibuffer_anchor.end.to_offset(&snapshot)
 5959        };
 5960        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5961            return None;
 5962        }
 5963
 5964        let old_text = buffer
 5965            .text_for_range(replace_range.clone())
 5966            .collect::<String>();
 5967        let lookbehind = newest_anchor
 5968            .start
 5969            .text_anchor
 5970            .to_offset(buffer)
 5971            .saturating_sub(replace_range.start);
 5972        let lookahead = replace_range
 5973            .end
 5974            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5975        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5976        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5977
 5978        let selections = self.selections.all::<usize>(cx);
 5979        let mut ranges = Vec::new();
 5980        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5981
 5982        for selection in &selections {
 5983            let range = if selection.id == newest_anchor.id {
 5984                replace_range_multibuffer.clone()
 5985            } else {
 5986                let mut range = selection.range();
 5987
 5988                // if prefix is present, don't duplicate it
 5989                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5990                    range.start = range.start.saturating_sub(lookbehind);
 5991
 5992                    // if suffix is also present, mimic the newest cursor and replace it
 5993                    if selection.id != newest_anchor.id
 5994                        && snapshot.contains_str_at(range.end, suffix)
 5995                    {
 5996                        range.end += lookahead;
 5997                    }
 5998                }
 5999                range
 6000            };
 6001
 6002            ranges.push(range.clone());
 6003
 6004            if !self.linked_edit_ranges.is_empty() {
 6005                let start_anchor = snapshot.anchor_before(range.start);
 6006                let end_anchor = snapshot.anchor_after(range.end);
 6007                if let Some(ranges) = self
 6008                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6009                {
 6010                    for (buffer, edits) in ranges {
 6011                        linked_edits
 6012                            .entry(buffer.clone())
 6013                            .or_default()
 6014                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6015                    }
 6016                }
 6017            }
 6018        }
 6019
 6020        let common_prefix_len = old_text
 6021            .chars()
 6022            .zip(new_text.chars())
 6023            .take_while(|(a, b)| a == b)
 6024            .map(|(a, _)| a.len_utf8())
 6025            .sum::<usize>();
 6026
 6027        cx.emit(EditorEvent::InputHandled {
 6028            utf16_range_to_replace: None,
 6029            text: new_text[common_prefix_len..].into(),
 6030        });
 6031
 6032        self.transact(window, cx, |editor, window, cx| {
 6033            if let Some(mut snippet) = snippet {
 6034                snippet.text = new_text.to_string();
 6035                editor
 6036                    .insert_snippet(&ranges, snippet, window, cx)
 6037                    .log_err();
 6038            } else {
 6039                editor.buffer.update(cx, |multi_buffer, cx| {
 6040                    let auto_indent = match completion.insert_text_mode {
 6041                        Some(InsertTextMode::AS_IS) => None,
 6042                        _ => editor.autoindent_mode.clone(),
 6043                    };
 6044                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6045                    multi_buffer.edit(edits, auto_indent, cx);
 6046                });
 6047            }
 6048            for (buffer, edits) in linked_edits {
 6049                buffer.update(cx, |buffer, cx| {
 6050                    let snapshot = buffer.snapshot();
 6051                    let edits = edits
 6052                        .into_iter()
 6053                        .map(|(range, text)| {
 6054                            use text::ToPoint as TP;
 6055                            let end_point = TP::to_point(&range.end, &snapshot);
 6056                            let start_point = TP::to_point(&range.start, &snapshot);
 6057                            (start_point..end_point, text)
 6058                        })
 6059                        .sorted_by_key(|(range, _)| range.start);
 6060                    buffer.edit(edits, None, cx);
 6061                })
 6062            }
 6063
 6064            editor.refresh_edit_prediction(true, false, window, cx);
 6065        });
 6066        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6067
 6068        let show_new_completions_on_confirm = completion
 6069            .confirm
 6070            .as_ref()
 6071            .is_some_and(|confirm| confirm(intent, window, cx));
 6072        if show_new_completions_on_confirm {
 6073            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6074        }
 6075
 6076        let provider = self.completion_provider.as_ref()?;
 6077        drop(completion);
 6078        let apply_edits = provider.apply_additional_edits_for_completion(
 6079            buffer_handle,
 6080            completions_menu.completions.clone(),
 6081            candidate_id,
 6082            true,
 6083            cx,
 6084        );
 6085
 6086        let editor_settings = EditorSettings::get_global(cx);
 6087        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6088            // After the code completion is finished, users often want to know what signatures are needed.
 6089            // so we should automatically call signature_help
 6090            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6091        }
 6092
 6093        Some(cx.foreground_executor().spawn(async move {
 6094            apply_edits.await?;
 6095            Ok(())
 6096        }))
 6097    }
 6098
 6099    pub fn toggle_code_actions(
 6100        &mut self,
 6101        action: &ToggleCodeActions,
 6102        window: &mut Window,
 6103        cx: &mut Context<Self>,
 6104    ) {
 6105        let quick_launch = action.quick_launch;
 6106        let mut context_menu = self.context_menu.borrow_mut();
 6107        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6108            if code_actions.deployed_from == action.deployed_from {
 6109                // Toggle if we're selecting the same one
 6110                *context_menu = None;
 6111                cx.notify();
 6112                return;
 6113            } else {
 6114                // Otherwise, clear it and start a new one
 6115                *context_menu = None;
 6116                cx.notify();
 6117            }
 6118        }
 6119        drop(context_menu);
 6120        let snapshot = self.snapshot(window, cx);
 6121        let deployed_from = action.deployed_from.clone();
 6122        let action = action.clone();
 6123        self.completion_tasks.clear();
 6124        self.discard_edit_prediction(false, cx);
 6125
 6126        let multibuffer_point = match &action.deployed_from {
 6127            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6128                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6129            }
 6130            _ => self.selections.newest::<Point>(cx).head(),
 6131        };
 6132        let Some((buffer, buffer_row)) = snapshot
 6133            .buffer_snapshot
 6134            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6135            .and_then(|(buffer_snapshot, range)| {
 6136                self.buffer()
 6137                    .read(cx)
 6138                    .buffer(buffer_snapshot.remote_id())
 6139                    .map(|buffer| (buffer, range.start.row))
 6140            })
 6141        else {
 6142            return;
 6143        };
 6144        let buffer_id = buffer.read(cx).remote_id();
 6145        let tasks = self
 6146            .tasks
 6147            .get(&(buffer_id, buffer_row))
 6148            .map(|t| Arc::new(t.to_owned()));
 6149
 6150        if !self.focus_handle.is_focused(window) {
 6151            return;
 6152        }
 6153        let project = self.project.clone();
 6154
 6155        let code_actions_task = match deployed_from {
 6156            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6157            _ => self.code_actions(buffer_row, window, cx),
 6158        };
 6159
 6160        let runnable_task = match deployed_from {
 6161            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6162            _ => {
 6163                let mut task_context_task = Task::ready(None);
 6164                if let Some(tasks) = &tasks
 6165                    && let Some(project) = project
 6166                {
 6167                    task_context_task =
 6168                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6169                }
 6170
 6171                cx.spawn_in(window, {
 6172                    let buffer = buffer.clone();
 6173                    async move |editor, cx| {
 6174                        let task_context = task_context_task.await;
 6175
 6176                        let resolved_tasks =
 6177                            tasks
 6178                                .zip(task_context.clone())
 6179                                .map(|(tasks, task_context)| ResolvedTasks {
 6180                                    templates: tasks.resolve(&task_context).collect(),
 6181                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6182                                        multibuffer_point.row,
 6183                                        tasks.column,
 6184                                    )),
 6185                                });
 6186                        let debug_scenarios = editor
 6187                            .update(cx, |editor, cx| {
 6188                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6189                            })?
 6190                            .await;
 6191                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6192                    }
 6193                })
 6194            }
 6195        };
 6196
 6197        cx.spawn_in(window, async move |editor, cx| {
 6198            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6199            let code_actions = code_actions_task.await;
 6200            let spawn_straight_away = quick_launch
 6201                && resolved_tasks
 6202                    .as_ref()
 6203                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6204                && code_actions
 6205                    .as_ref()
 6206                    .is_none_or(|actions| actions.is_empty())
 6207                && debug_scenarios.is_empty();
 6208
 6209            editor.update_in(cx, |editor, window, cx| {
 6210                crate::hover_popover::hide_hover(editor, cx);
 6211                let actions = CodeActionContents::new(
 6212                    resolved_tasks,
 6213                    code_actions,
 6214                    debug_scenarios,
 6215                    task_context.unwrap_or_default(),
 6216                );
 6217
 6218                // Don't show the menu if there are no actions available
 6219                if actions.is_empty() {
 6220                    cx.notify();
 6221                    return Task::ready(Ok(()));
 6222                }
 6223
 6224                *editor.context_menu.borrow_mut() =
 6225                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6226                        buffer,
 6227                        actions,
 6228                        selected_item: Default::default(),
 6229                        scroll_handle: UniformListScrollHandle::default(),
 6230                        deployed_from,
 6231                    }));
 6232                cx.notify();
 6233                if spawn_straight_away
 6234                    && let Some(task) = editor.confirm_code_action(
 6235                        &ConfirmCodeAction { item_ix: Some(0) },
 6236                        window,
 6237                        cx,
 6238                    )
 6239                {
 6240                    return task;
 6241                }
 6242
 6243                Task::ready(Ok(()))
 6244            })
 6245        })
 6246        .detach_and_log_err(cx);
 6247    }
 6248
 6249    fn debug_scenarios(
 6250        &mut self,
 6251        resolved_tasks: &Option<ResolvedTasks>,
 6252        buffer: &Entity<Buffer>,
 6253        cx: &mut App,
 6254    ) -> Task<Vec<task::DebugScenario>> {
 6255        maybe!({
 6256            let project = self.project()?;
 6257            let dap_store = project.read(cx).dap_store();
 6258            let mut scenarios = vec![];
 6259            let resolved_tasks = resolved_tasks.as_ref()?;
 6260            let buffer = buffer.read(cx);
 6261            let language = buffer.language()?;
 6262            let file = buffer.file();
 6263            let debug_adapter = language_settings(language.name().into(), file, cx)
 6264                .debuggers
 6265                .first()
 6266                .map(SharedString::from)
 6267                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6268
 6269            dap_store.update(cx, |dap_store, cx| {
 6270                for (_, task) in &resolved_tasks.templates {
 6271                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6272                        task.original_task().clone(),
 6273                        debug_adapter.clone().into(),
 6274                        task.display_label().to_owned().into(),
 6275                        cx,
 6276                    );
 6277                    scenarios.push(maybe_scenario);
 6278                }
 6279            });
 6280            Some(cx.background_spawn(async move {
 6281                futures::future::join_all(scenarios)
 6282                    .await
 6283                    .into_iter()
 6284                    .flatten()
 6285                    .collect::<Vec<_>>()
 6286            }))
 6287        })
 6288        .unwrap_or_else(|| Task::ready(vec![]))
 6289    }
 6290
 6291    fn code_actions(
 6292        &mut self,
 6293        buffer_row: u32,
 6294        window: &mut Window,
 6295        cx: &mut Context<Self>,
 6296    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6297        let mut task = self.code_actions_task.take();
 6298        cx.spawn_in(window, async move |editor, cx| {
 6299            while let Some(prev_task) = task {
 6300                prev_task.await.log_err();
 6301                task = editor
 6302                    .update(cx, |this, _| this.code_actions_task.take())
 6303                    .ok()?;
 6304            }
 6305
 6306            editor
 6307                .update(cx, |editor, cx| {
 6308                    editor
 6309                        .available_code_actions
 6310                        .clone()
 6311                        .and_then(|(location, code_actions)| {
 6312                            let snapshot = location.buffer.read(cx).snapshot();
 6313                            let point_range = location.range.to_point(&snapshot);
 6314                            let point_range = point_range.start.row..=point_range.end.row;
 6315                            if point_range.contains(&buffer_row) {
 6316                                Some(code_actions)
 6317                            } else {
 6318                                None
 6319                            }
 6320                        })
 6321                })
 6322                .ok()
 6323                .flatten()
 6324        })
 6325    }
 6326
 6327    pub fn confirm_code_action(
 6328        &mut self,
 6329        action: &ConfirmCodeAction,
 6330        window: &mut Window,
 6331        cx: &mut Context<Self>,
 6332    ) -> Option<Task<Result<()>>> {
 6333        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6334
 6335        let actions_menu =
 6336            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6337                menu
 6338            } else {
 6339                return None;
 6340            };
 6341
 6342        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6343        let action = actions_menu.actions.get(action_ix)?;
 6344        let title = action.label();
 6345        let buffer = actions_menu.buffer;
 6346        let workspace = self.workspace()?;
 6347
 6348        match action {
 6349            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6350                workspace.update(cx, |workspace, cx| {
 6351                    workspace.schedule_resolved_task(
 6352                        task_source_kind,
 6353                        resolved_task,
 6354                        false,
 6355                        window,
 6356                        cx,
 6357                    );
 6358
 6359                    Some(Task::ready(Ok(())))
 6360                })
 6361            }
 6362            CodeActionsItem::CodeAction {
 6363                excerpt_id,
 6364                action,
 6365                provider,
 6366            } => {
 6367                let apply_code_action =
 6368                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6369                let workspace = workspace.downgrade();
 6370                Some(cx.spawn_in(window, async move |editor, cx| {
 6371                    let project_transaction = apply_code_action.await?;
 6372                    Self::open_project_transaction(
 6373                        &editor,
 6374                        workspace,
 6375                        project_transaction,
 6376                        title,
 6377                        cx,
 6378                    )
 6379                    .await
 6380                }))
 6381            }
 6382            CodeActionsItem::DebugScenario(scenario) => {
 6383                let context = actions_menu.actions.context;
 6384
 6385                workspace.update(cx, |workspace, cx| {
 6386                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6387                    workspace.start_debug_session(
 6388                        scenario,
 6389                        context,
 6390                        Some(buffer),
 6391                        None,
 6392                        window,
 6393                        cx,
 6394                    );
 6395                });
 6396                Some(Task::ready(Ok(())))
 6397            }
 6398        }
 6399    }
 6400
 6401    pub async fn open_project_transaction(
 6402        editor: &WeakEntity<Editor>,
 6403        workspace: WeakEntity<Workspace>,
 6404        transaction: ProjectTransaction,
 6405        title: String,
 6406        cx: &mut AsyncWindowContext,
 6407    ) -> Result<()> {
 6408        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6409        cx.update(|_, cx| {
 6410            entries.sort_unstable_by_key(|(buffer, _)| {
 6411                buffer.read(cx).file().map(|f| f.path().clone())
 6412            });
 6413        })?;
 6414
 6415        // If the project transaction's edits are all contained within this editor, then
 6416        // avoid opening a new editor to display them.
 6417
 6418        if let Some((buffer, transaction)) = entries.first() {
 6419            if entries.len() == 1 {
 6420                let excerpt = editor.update(cx, |editor, cx| {
 6421                    editor
 6422                        .buffer()
 6423                        .read(cx)
 6424                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6425                })?;
 6426                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6427                    && excerpted_buffer == *buffer
 6428                {
 6429                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6430                        let excerpt_range = excerpt_range.to_offset(buffer);
 6431                        buffer
 6432                            .edited_ranges_for_transaction::<usize>(transaction)
 6433                            .all(|range| {
 6434                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6435                            })
 6436                    })?;
 6437
 6438                    if all_edits_within_excerpt {
 6439                        return Ok(());
 6440                    }
 6441                }
 6442            }
 6443        } else {
 6444            return Ok(());
 6445        }
 6446
 6447        let mut ranges_to_highlight = Vec::new();
 6448        let excerpt_buffer = cx.new(|cx| {
 6449            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6450            for (buffer_handle, transaction) in &entries {
 6451                let edited_ranges = buffer_handle
 6452                    .read(cx)
 6453                    .edited_ranges_for_transaction::<Point>(transaction)
 6454                    .collect::<Vec<_>>();
 6455                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6456                    PathKey::for_buffer(buffer_handle, cx),
 6457                    buffer_handle.clone(),
 6458                    edited_ranges,
 6459                    multibuffer_context_lines(cx),
 6460                    cx,
 6461                );
 6462
 6463                ranges_to_highlight.extend(ranges);
 6464            }
 6465            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6466            multibuffer
 6467        })?;
 6468
 6469        workspace.update_in(cx, |workspace, window, cx| {
 6470            let project = workspace.project().clone();
 6471            let editor =
 6472                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6473            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6474            editor.update(cx, |editor, cx| {
 6475                editor.highlight_background::<Self>(
 6476                    &ranges_to_highlight,
 6477                    |theme| theme.colors().editor_highlighted_line_background,
 6478                    cx,
 6479                );
 6480            });
 6481        })?;
 6482
 6483        Ok(())
 6484    }
 6485
 6486    pub fn clear_code_action_providers(&mut self) {
 6487        self.code_action_providers.clear();
 6488        self.available_code_actions.take();
 6489    }
 6490
 6491    pub fn add_code_action_provider(
 6492        &mut self,
 6493        provider: Rc<dyn CodeActionProvider>,
 6494        window: &mut Window,
 6495        cx: &mut Context<Self>,
 6496    ) {
 6497        if self
 6498            .code_action_providers
 6499            .iter()
 6500            .any(|existing_provider| existing_provider.id() == provider.id())
 6501        {
 6502            return;
 6503        }
 6504
 6505        self.code_action_providers.push(provider);
 6506        self.refresh_code_actions(window, cx);
 6507    }
 6508
 6509    pub fn remove_code_action_provider(
 6510        &mut self,
 6511        id: Arc<str>,
 6512        window: &mut Window,
 6513        cx: &mut Context<Self>,
 6514    ) {
 6515        self.code_action_providers
 6516            .retain(|provider| provider.id() != id);
 6517        self.refresh_code_actions(window, cx);
 6518    }
 6519
 6520    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6521        !self.code_action_providers.is_empty()
 6522            && EditorSettings::get_global(cx).toolbar.code_actions
 6523    }
 6524
 6525    pub fn has_available_code_actions(&self) -> bool {
 6526        self.available_code_actions
 6527            .as_ref()
 6528            .is_some_and(|(_, actions)| !actions.is_empty())
 6529    }
 6530
 6531    fn render_inline_code_actions(
 6532        &self,
 6533        icon_size: ui::IconSize,
 6534        display_row: DisplayRow,
 6535        is_active: bool,
 6536        cx: &mut Context<Self>,
 6537    ) -> AnyElement {
 6538        let show_tooltip = !self.context_menu_visible();
 6539        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6540            .icon_size(icon_size)
 6541            .shape(ui::IconButtonShape::Square)
 6542            .icon_color(ui::Color::Hidden)
 6543            .toggle_state(is_active)
 6544            .when(show_tooltip, |this| {
 6545                this.tooltip({
 6546                    let focus_handle = self.focus_handle.clone();
 6547                    move |window, cx| {
 6548                        Tooltip::for_action_in(
 6549                            "Toggle Code Actions",
 6550                            &ToggleCodeActions {
 6551                                deployed_from: None,
 6552                                quick_launch: false,
 6553                            },
 6554                            &focus_handle,
 6555                            window,
 6556                            cx,
 6557                        )
 6558                    }
 6559                })
 6560            })
 6561            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6562                window.focus(&editor.focus_handle(cx));
 6563                editor.toggle_code_actions(
 6564                    &crate::actions::ToggleCodeActions {
 6565                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6566                            display_row,
 6567                        )),
 6568                        quick_launch: false,
 6569                    },
 6570                    window,
 6571                    cx,
 6572                );
 6573            }))
 6574            .into_any_element()
 6575    }
 6576
 6577    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6578        &self.context_menu
 6579    }
 6580
 6581    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6582        let newest_selection = self.selections.newest_anchor().clone();
 6583        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6584        let buffer = self.buffer.read(cx);
 6585        if newest_selection.head().diff_base_anchor.is_some() {
 6586            return None;
 6587        }
 6588        let (start_buffer, start) =
 6589            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6590        let (end_buffer, end) =
 6591            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6592        if start_buffer != end_buffer {
 6593            return None;
 6594        }
 6595
 6596        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6597            cx.background_executor()
 6598                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6599                .await;
 6600
 6601            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6602                let providers = this.code_action_providers.clone();
 6603                let tasks = this
 6604                    .code_action_providers
 6605                    .iter()
 6606                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6607                    .collect::<Vec<_>>();
 6608                (providers, tasks)
 6609            })?;
 6610
 6611            let mut actions = Vec::new();
 6612            for (provider, provider_actions) in
 6613                providers.into_iter().zip(future::join_all(tasks).await)
 6614            {
 6615                if let Some(provider_actions) = provider_actions.log_err() {
 6616                    actions.extend(provider_actions.into_iter().map(|action| {
 6617                        AvailableCodeAction {
 6618                            excerpt_id: newest_selection.start.excerpt_id,
 6619                            action,
 6620                            provider: provider.clone(),
 6621                        }
 6622                    }));
 6623                }
 6624            }
 6625
 6626            this.update(cx, |this, cx| {
 6627                this.available_code_actions = if actions.is_empty() {
 6628                    None
 6629                } else {
 6630                    Some((
 6631                        Location {
 6632                            buffer: start_buffer,
 6633                            range: start..end,
 6634                        },
 6635                        actions.into(),
 6636                    ))
 6637                };
 6638                cx.notify();
 6639            })
 6640        }));
 6641        None
 6642    }
 6643
 6644    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6645        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6646            self.show_git_blame_inline = false;
 6647
 6648            self.show_git_blame_inline_delay_task =
 6649                Some(cx.spawn_in(window, async move |this, cx| {
 6650                    cx.background_executor().timer(delay).await;
 6651
 6652                    this.update(cx, |this, cx| {
 6653                        this.show_git_blame_inline = true;
 6654                        cx.notify();
 6655                    })
 6656                    .log_err();
 6657                }));
 6658        }
 6659    }
 6660
 6661    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6662        let snapshot = self.snapshot(window, cx);
 6663        let cursor = self.selections.newest::<Point>(cx).head();
 6664        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6665        else {
 6666            return;
 6667        };
 6668
 6669        let Some(blame) = self.blame.as_ref() else {
 6670            return;
 6671        };
 6672
 6673        let row_info = RowInfo {
 6674            buffer_id: Some(buffer.remote_id()),
 6675            buffer_row: Some(point.row),
 6676            ..Default::default()
 6677        };
 6678        let Some((buffer, blame_entry)) = blame
 6679            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6680            .flatten()
 6681        else {
 6682            return;
 6683        };
 6684
 6685        let anchor = self.selections.newest_anchor().head();
 6686        let position = self.to_pixel_point(anchor, &snapshot, window);
 6687        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6688            self.show_blame_popover(
 6689                buffer,
 6690                &blame_entry,
 6691                position + last_bounds.origin,
 6692                true,
 6693                cx,
 6694            );
 6695        };
 6696    }
 6697
 6698    fn show_blame_popover(
 6699        &mut self,
 6700        buffer: BufferId,
 6701        blame_entry: &BlameEntry,
 6702        position: gpui::Point<Pixels>,
 6703        ignore_timeout: bool,
 6704        cx: &mut Context<Self>,
 6705    ) {
 6706        if let Some(state) = &mut self.inline_blame_popover {
 6707            state.hide_task.take();
 6708        } else {
 6709            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6710            let blame_entry = blame_entry.clone();
 6711            let show_task = cx.spawn(async move |editor, cx| {
 6712                if !ignore_timeout {
 6713                    cx.background_executor()
 6714                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6715                        .await;
 6716                }
 6717                editor
 6718                    .update(cx, |editor, cx| {
 6719                        editor.inline_blame_popover_show_task.take();
 6720                        let Some(blame) = editor.blame.as_ref() else {
 6721                            return;
 6722                        };
 6723                        let blame = blame.read(cx);
 6724                        let details = blame.details_for_entry(buffer, &blame_entry);
 6725                        let markdown = cx.new(|cx| {
 6726                            Markdown::new(
 6727                                details
 6728                                    .as_ref()
 6729                                    .map(|message| message.message.clone())
 6730                                    .unwrap_or_default(),
 6731                                None,
 6732                                None,
 6733                                cx,
 6734                            )
 6735                        });
 6736                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6737                            position,
 6738                            hide_task: None,
 6739                            popover_bounds: None,
 6740                            popover_state: InlineBlamePopoverState {
 6741                                scroll_handle: ScrollHandle::new(),
 6742                                commit_message: details,
 6743                                markdown,
 6744                            },
 6745                            keyboard_grace: ignore_timeout,
 6746                        });
 6747                        cx.notify();
 6748                    })
 6749                    .ok();
 6750            });
 6751            self.inline_blame_popover_show_task = Some(show_task);
 6752        }
 6753    }
 6754
 6755    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6756        self.inline_blame_popover_show_task.take();
 6757        if let Some(state) = &mut self.inline_blame_popover {
 6758            let hide_task = cx.spawn(async move |editor, cx| {
 6759                cx.background_executor()
 6760                    .timer(std::time::Duration::from_millis(100))
 6761                    .await;
 6762                editor
 6763                    .update(cx, |editor, cx| {
 6764                        editor.inline_blame_popover.take();
 6765                        cx.notify();
 6766                    })
 6767                    .ok();
 6768            });
 6769            state.hide_task = Some(hide_task);
 6770        }
 6771    }
 6772
 6773    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6774        if self.pending_rename.is_some() {
 6775            return None;
 6776        }
 6777
 6778        let provider = self.semantics_provider.clone()?;
 6779        let buffer = self.buffer.read(cx);
 6780        let newest_selection = self.selections.newest_anchor().clone();
 6781        let cursor_position = newest_selection.head();
 6782        let (cursor_buffer, cursor_buffer_position) =
 6783            buffer.text_anchor_for_position(cursor_position, cx)?;
 6784        let (tail_buffer, tail_buffer_position) =
 6785            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6786        if cursor_buffer != tail_buffer {
 6787            return None;
 6788        }
 6789
 6790        let snapshot = cursor_buffer.read(cx).snapshot();
 6791        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6792        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6793        if start_word_range != end_word_range {
 6794            self.document_highlights_task.take();
 6795            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6796            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6797            return None;
 6798        }
 6799
 6800        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6801        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6802            cx.background_executor()
 6803                .timer(Duration::from_millis(debounce))
 6804                .await;
 6805
 6806            let highlights = if let Some(highlights) = cx
 6807                .update(|cx| {
 6808                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6809                })
 6810                .ok()
 6811                .flatten()
 6812            {
 6813                highlights.await.log_err()
 6814            } else {
 6815                None
 6816            };
 6817
 6818            if let Some(highlights) = highlights {
 6819                this.update(cx, |this, cx| {
 6820                    if this.pending_rename.is_some() {
 6821                        return;
 6822                    }
 6823
 6824                    let buffer = this.buffer.read(cx);
 6825                    if buffer
 6826                        .text_anchor_for_position(cursor_position, cx)
 6827                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6828                    {
 6829                        return;
 6830                    }
 6831
 6832                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6833                    let mut write_ranges = Vec::new();
 6834                    let mut read_ranges = Vec::new();
 6835                    for highlight in highlights {
 6836                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6837                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6838                        {
 6839                            let start = highlight
 6840                                .range
 6841                                .start
 6842                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6843                            let end = highlight
 6844                                .range
 6845                                .end
 6846                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6847                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6848                                continue;
 6849                            }
 6850
 6851                            let range = Anchor {
 6852                                buffer_id: Some(buffer_id),
 6853                                excerpt_id,
 6854                                text_anchor: start,
 6855                                diff_base_anchor: None,
 6856                            }..Anchor {
 6857                                buffer_id: Some(buffer_id),
 6858                                excerpt_id,
 6859                                text_anchor: end,
 6860                                diff_base_anchor: None,
 6861                            };
 6862                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6863                                write_ranges.push(range);
 6864                            } else {
 6865                                read_ranges.push(range);
 6866                            }
 6867                        }
 6868                    }
 6869
 6870                    this.highlight_background::<DocumentHighlightRead>(
 6871                        &read_ranges,
 6872                        |theme| theme.colors().editor_document_highlight_read_background,
 6873                        cx,
 6874                    );
 6875                    this.highlight_background::<DocumentHighlightWrite>(
 6876                        &write_ranges,
 6877                        |theme| theme.colors().editor_document_highlight_write_background,
 6878                        cx,
 6879                    );
 6880                    cx.notify();
 6881                })
 6882                .log_err();
 6883            }
 6884        }));
 6885        None
 6886    }
 6887
 6888    fn prepare_highlight_query_from_selection(
 6889        &mut self,
 6890        cx: &mut Context<Editor>,
 6891    ) -> Option<(String, Range<Anchor>)> {
 6892        if matches!(self.mode, EditorMode::SingleLine) {
 6893            return None;
 6894        }
 6895        if !EditorSettings::get_global(cx).selection_highlight {
 6896            return None;
 6897        }
 6898        if self.selections.count() != 1 || self.selections.line_mode {
 6899            return None;
 6900        }
 6901        let selection = self.selections.newest::<Point>(cx);
 6902        if selection.is_empty() || selection.start.row != selection.end.row {
 6903            return None;
 6904        }
 6905        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6906        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6907        let query = multi_buffer_snapshot
 6908            .text_for_range(selection_anchor_range.clone())
 6909            .collect::<String>();
 6910        if query.trim().is_empty() {
 6911            return None;
 6912        }
 6913        Some((query, selection_anchor_range))
 6914    }
 6915
 6916    fn update_selection_occurrence_highlights(
 6917        &mut self,
 6918        query_text: String,
 6919        query_range: Range<Anchor>,
 6920        multi_buffer_range_to_query: Range<Point>,
 6921        use_debounce: bool,
 6922        window: &mut Window,
 6923        cx: &mut Context<Editor>,
 6924    ) -> Task<()> {
 6925        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6926        cx.spawn_in(window, async move |editor, cx| {
 6927            if use_debounce {
 6928                cx.background_executor()
 6929                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6930                    .await;
 6931            }
 6932            let match_task = cx.background_spawn(async move {
 6933                let buffer_ranges = multi_buffer_snapshot
 6934                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6935                    .into_iter()
 6936                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6937                let mut match_ranges = Vec::new();
 6938                let Ok(regex) = project::search::SearchQuery::text(
 6939                    query_text.clone(),
 6940                    false,
 6941                    false,
 6942                    false,
 6943                    Default::default(),
 6944                    Default::default(),
 6945                    false,
 6946                    None,
 6947                ) else {
 6948                    return Vec::default();
 6949                };
 6950                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6951                    match_ranges.extend(
 6952                        regex
 6953                            .search(buffer_snapshot, Some(search_range.clone()))
 6954                            .await
 6955                            .into_iter()
 6956                            .filter_map(|match_range| {
 6957                                let match_start = buffer_snapshot
 6958                                    .anchor_after(search_range.start + match_range.start);
 6959                                let match_end = buffer_snapshot
 6960                                    .anchor_before(search_range.start + match_range.end);
 6961                                let match_anchor_range = Anchor::range_in_buffer(
 6962                                    excerpt_id,
 6963                                    buffer_snapshot.remote_id(),
 6964                                    match_start..match_end,
 6965                                );
 6966                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6967                            }),
 6968                    );
 6969                }
 6970                match_ranges
 6971            });
 6972            let match_ranges = match_task.await;
 6973            editor
 6974                .update_in(cx, |editor, _, cx| {
 6975                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6976                    if !match_ranges.is_empty() {
 6977                        editor.highlight_background::<SelectedTextHighlight>(
 6978                            &match_ranges,
 6979                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6980                            cx,
 6981                        )
 6982                    }
 6983                })
 6984                .log_err();
 6985        })
 6986    }
 6987
 6988    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6989        struct NewlineFold;
 6990        let type_id = std::any::TypeId::of::<NewlineFold>();
 6991        if !self.mode.is_single_line() {
 6992            return;
 6993        }
 6994        let snapshot = self.snapshot(window, cx);
 6995        if snapshot.buffer_snapshot.max_point().row == 0 {
 6996            return;
 6997        }
 6998        let task = cx.background_spawn(async move {
 6999            let new_newlines = snapshot
 7000                .buffer_chars_at(0)
 7001                .filter_map(|(c, i)| {
 7002                    if c == '\n' {
 7003                        Some(
 7004                            snapshot.buffer_snapshot.anchor_after(i)
 7005                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7006                        )
 7007                    } else {
 7008                        None
 7009                    }
 7010                })
 7011                .collect::<Vec<_>>();
 7012            let existing_newlines = snapshot
 7013                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7014                .filter_map(|fold| {
 7015                    if fold.placeholder.type_tag == Some(type_id) {
 7016                        Some(fold.range.start..fold.range.end)
 7017                    } else {
 7018                        None
 7019                    }
 7020                })
 7021                .collect::<Vec<_>>();
 7022
 7023            (new_newlines, existing_newlines)
 7024        });
 7025        self.folding_newlines = cx.spawn(async move |this, cx| {
 7026            let (new_newlines, existing_newlines) = task.await;
 7027            if new_newlines == existing_newlines {
 7028                return;
 7029            }
 7030            let placeholder = FoldPlaceholder {
 7031                render: Arc::new(move |_, _, cx| {
 7032                    div()
 7033                        .bg(cx.theme().status().hint_background)
 7034                        .border_b_1()
 7035                        .size_full()
 7036                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7037                        .border_color(cx.theme().status().hint)
 7038                        .child("\\n")
 7039                        .into_any()
 7040                }),
 7041                constrain_width: false,
 7042                merge_adjacent: false,
 7043                type_tag: Some(type_id),
 7044            };
 7045            let creases = new_newlines
 7046                .into_iter()
 7047                .map(|range| Crease::simple(range, placeholder.clone()))
 7048                .collect();
 7049            this.update(cx, |this, cx| {
 7050                this.display_map.update(cx, |display_map, cx| {
 7051                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7052                    display_map.fold(creases, cx);
 7053                });
 7054            })
 7055            .ok();
 7056        });
 7057    }
 7058
 7059    fn refresh_selected_text_highlights(
 7060        &mut self,
 7061        on_buffer_edit: bool,
 7062        window: &mut Window,
 7063        cx: &mut Context<Editor>,
 7064    ) {
 7065        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7066        else {
 7067            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7068            self.quick_selection_highlight_task.take();
 7069            self.debounced_selection_highlight_task.take();
 7070            return;
 7071        };
 7072        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7073        if on_buffer_edit
 7074            || self
 7075                .quick_selection_highlight_task
 7076                .as_ref()
 7077                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7078        {
 7079            let multi_buffer_visible_start = self
 7080                .scroll_manager
 7081                .anchor()
 7082                .anchor
 7083                .to_point(&multi_buffer_snapshot);
 7084            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7085                multi_buffer_visible_start
 7086                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7087                Bias::Left,
 7088            );
 7089            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7090            self.quick_selection_highlight_task = Some((
 7091                query_range.clone(),
 7092                self.update_selection_occurrence_highlights(
 7093                    query_text.clone(),
 7094                    query_range.clone(),
 7095                    multi_buffer_visible_range,
 7096                    false,
 7097                    window,
 7098                    cx,
 7099                ),
 7100            ));
 7101        }
 7102        if on_buffer_edit
 7103            || self
 7104                .debounced_selection_highlight_task
 7105                .as_ref()
 7106                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7107        {
 7108            let multi_buffer_start = multi_buffer_snapshot
 7109                .anchor_before(0)
 7110                .to_point(&multi_buffer_snapshot);
 7111            let multi_buffer_end = multi_buffer_snapshot
 7112                .anchor_after(multi_buffer_snapshot.len())
 7113                .to_point(&multi_buffer_snapshot);
 7114            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7115            self.debounced_selection_highlight_task = Some((
 7116                query_range.clone(),
 7117                self.update_selection_occurrence_highlights(
 7118                    query_text,
 7119                    query_range,
 7120                    multi_buffer_full_range,
 7121                    true,
 7122                    window,
 7123                    cx,
 7124                ),
 7125            ));
 7126        }
 7127    }
 7128
 7129    pub fn refresh_edit_prediction(
 7130        &mut self,
 7131        debounce: bool,
 7132        user_requested: bool,
 7133        window: &mut Window,
 7134        cx: &mut Context<Self>,
 7135    ) -> Option<()> {
 7136        if DisableAiSettings::get_global(cx).disable_ai {
 7137            return None;
 7138        }
 7139
 7140        let provider = self.edit_prediction_provider()?;
 7141        let cursor = self.selections.newest_anchor().head();
 7142        let (buffer, cursor_buffer_position) =
 7143            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7144
 7145        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7146            self.discard_edit_prediction(false, cx);
 7147            return None;
 7148        }
 7149
 7150        if !user_requested
 7151            && (!self.should_show_edit_predictions()
 7152                || !self.is_focused(window)
 7153                || buffer.read(cx).is_empty())
 7154        {
 7155            self.discard_edit_prediction(false, cx);
 7156            return None;
 7157        }
 7158
 7159        self.update_visible_edit_prediction(window, cx);
 7160        provider.refresh(
 7161            self.project.clone(),
 7162            buffer,
 7163            cursor_buffer_position,
 7164            debounce,
 7165            cx,
 7166        );
 7167        Some(())
 7168    }
 7169
 7170    fn show_edit_predictions_in_menu(&self) -> bool {
 7171        match self.edit_prediction_settings {
 7172            EditPredictionSettings::Disabled => false,
 7173            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7174        }
 7175    }
 7176
 7177    pub fn edit_predictions_enabled(&self) -> bool {
 7178        match self.edit_prediction_settings {
 7179            EditPredictionSettings::Disabled => false,
 7180            EditPredictionSettings::Enabled { .. } => true,
 7181        }
 7182    }
 7183
 7184    fn edit_prediction_requires_modifier(&self) -> bool {
 7185        match self.edit_prediction_settings {
 7186            EditPredictionSettings::Disabled => false,
 7187            EditPredictionSettings::Enabled {
 7188                preview_requires_modifier,
 7189                ..
 7190            } => preview_requires_modifier,
 7191        }
 7192    }
 7193
 7194    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7195        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7196            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7197            self.discard_edit_prediction(false, cx);
 7198        } else {
 7199            let selection = self.selections.newest_anchor();
 7200            let cursor = selection.head();
 7201
 7202            if let Some((buffer, cursor_buffer_position)) =
 7203                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7204            {
 7205                self.edit_prediction_settings =
 7206                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7207            }
 7208        }
 7209    }
 7210
 7211    fn edit_prediction_settings_at_position(
 7212        &self,
 7213        buffer: &Entity<Buffer>,
 7214        buffer_position: language::Anchor,
 7215        cx: &App,
 7216    ) -> EditPredictionSettings {
 7217        if !self.mode.is_full()
 7218            || !self.show_edit_predictions_override.unwrap_or(true)
 7219            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7220        {
 7221            return EditPredictionSettings::Disabled;
 7222        }
 7223
 7224        let buffer = buffer.read(cx);
 7225
 7226        let file = buffer.file();
 7227
 7228        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7229            return EditPredictionSettings::Disabled;
 7230        };
 7231
 7232        let by_provider = matches!(
 7233            self.menu_edit_predictions_policy,
 7234            MenuEditPredictionsPolicy::ByProvider
 7235        );
 7236
 7237        let show_in_menu = by_provider
 7238            && self
 7239                .edit_prediction_provider
 7240                .as_ref()
 7241                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7242
 7243        let preview_requires_modifier =
 7244            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7245
 7246        EditPredictionSettings::Enabled {
 7247            show_in_menu,
 7248            preview_requires_modifier,
 7249        }
 7250    }
 7251
 7252    fn should_show_edit_predictions(&self) -> bool {
 7253        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7254    }
 7255
 7256    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7257        matches!(
 7258            self.edit_prediction_preview,
 7259            EditPredictionPreview::Active { .. }
 7260        )
 7261    }
 7262
 7263    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7264        let cursor = self.selections.newest_anchor().head();
 7265        if let Some((buffer, cursor_position)) =
 7266            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7267        {
 7268            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7269        } else {
 7270            false
 7271        }
 7272    }
 7273
 7274    pub fn supports_minimap(&self, cx: &App) -> bool {
 7275        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7276    }
 7277
 7278    fn edit_predictions_enabled_in_buffer(
 7279        &self,
 7280        buffer: &Entity<Buffer>,
 7281        buffer_position: language::Anchor,
 7282        cx: &App,
 7283    ) -> bool {
 7284        maybe!({
 7285            if self.read_only(cx) {
 7286                return Some(false);
 7287            }
 7288            let provider = self.edit_prediction_provider()?;
 7289            if !provider.is_enabled(buffer, buffer_position, cx) {
 7290                return Some(false);
 7291            }
 7292            let buffer = buffer.read(cx);
 7293            let Some(file) = buffer.file() else {
 7294                return Some(true);
 7295            };
 7296            let settings = all_language_settings(Some(file), cx);
 7297            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7298        })
 7299        .unwrap_or(false)
 7300    }
 7301
 7302    fn cycle_edit_prediction(
 7303        &mut self,
 7304        direction: Direction,
 7305        window: &mut Window,
 7306        cx: &mut Context<Self>,
 7307    ) -> Option<()> {
 7308        let provider = self.edit_prediction_provider()?;
 7309        let cursor = self.selections.newest_anchor().head();
 7310        let (buffer, cursor_buffer_position) =
 7311            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7312        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7313            return None;
 7314        }
 7315
 7316        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7317        self.update_visible_edit_prediction(window, cx);
 7318
 7319        Some(())
 7320    }
 7321
 7322    pub fn show_edit_prediction(
 7323        &mut self,
 7324        _: &ShowEditPrediction,
 7325        window: &mut Window,
 7326        cx: &mut Context<Self>,
 7327    ) {
 7328        if !self.has_active_edit_prediction() {
 7329            self.refresh_edit_prediction(false, true, window, cx);
 7330            return;
 7331        }
 7332
 7333        self.update_visible_edit_prediction(window, cx);
 7334    }
 7335
 7336    pub fn display_cursor_names(
 7337        &mut self,
 7338        _: &DisplayCursorNames,
 7339        window: &mut Window,
 7340        cx: &mut Context<Self>,
 7341    ) {
 7342        self.show_cursor_names(window, cx);
 7343    }
 7344
 7345    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7346        self.show_cursor_names = true;
 7347        cx.notify();
 7348        cx.spawn_in(window, async move |this, cx| {
 7349            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7350            this.update(cx, |this, cx| {
 7351                this.show_cursor_names = false;
 7352                cx.notify()
 7353            })
 7354            .ok()
 7355        })
 7356        .detach();
 7357    }
 7358
 7359    pub fn next_edit_prediction(
 7360        &mut self,
 7361        _: &NextEditPrediction,
 7362        window: &mut Window,
 7363        cx: &mut Context<Self>,
 7364    ) {
 7365        if self.has_active_edit_prediction() {
 7366            self.cycle_edit_prediction(Direction::Next, window, cx);
 7367        } else {
 7368            let is_copilot_disabled = self
 7369                .refresh_edit_prediction(false, true, window, cx)
 7370                .is_none();
 7371            if is_copilot_disabled {
 7372                cx.propagate();
 7373            }
 7374        }
 7375    }
 7376
 7377    pub fn previous_edit_prediction(
 7378        &mut self,
 7379        _: &PreviousEditPrediction,
 7380        window: &mut Window,
 7381        cx: &mut Context<Self>,
 7382    ) {
 7383        if self.has_active_edit_prediction() {
 7384            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7385        } else {
 7386            let is_copilot_disabled = self
 7387                .refresh_edit_prediction(false, true, window, cx)
 7388                .is_none();
 7389            if is_copilot_disabled {
 7390                cx.propagate();
 7391            }
 7392        }
 7393    }
 7394
 7395    pub fn accept_edit_prediction(
 7396        &mut self,
 7397        _: &AcceptEditPrediction,
 7398        window: &mut Window,
 7399        cx: &mut Context<Self>,
 7400    ) {
 7401        if self.show_edit_predictions_in_menu() {
 7402            self.hide_context_menu(window, cx);
 7403        }
 7404
 7405        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7406            return;
 7407        };
 7408
 7409        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7410
 7411        match &active_edit_prediction.completion {
 7412            EditPrediction::Move { target, .. } => {
 7413                let target = *target;
 7414
 7415                if let Some(position_map) = &self.last_position_map {
 7416                    if position_map
 7417                        .visible_row_range
 7418                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7419                        || !self.edit_prediction_requires_modifier()
 7420                    {
 7421                        self.unfold_ranges(&[target..target], true, false, cx);
 7422                        // Note that this is also done in vim's handler of the Tab action.
 7423                        self.change_selections(
 7424                            SelectionEffects::scroll(Autoscroll::newest()),
 7425                            window,
 7426                            cx,
 7427                            |selections| {
 7428                                selections.select_anchor_ranges([target..target]);
 7429                            },
 7430                        );
 7431                        self.clear_row_highlights::<EditPredictionPreview>();
 7432
 7433                        self.edit_prediction_preview
 7434                            .set_previous_scroll_position(None);
 7435                    } else {
 7436                        self.edit_prediction_preview
 7437                            .set_previous_scroll_position(Some(
 7438                                position_map.snapshot.scroll_anchor,
 7439                            ));
 7440
 7441                        self.highlight_rows::<EditPredictionPreview>(
 7442                            target..target,
 7443                            cx.theme().colors().editor_highlighted_line_background,
 7444                            RowHighlightOptions {
 7445                                autoscroll: true,
 7446                                ..Default::default()
 7447                            },
 7448                            cx,
 7449                        );
 7450                        self.request_autoscroll(Autoscroll::fit(), cx);
 7451                    }
 7452                }
 7453            }
 7454            EditPrediction::Edit { edits, .. } => {
 7455                if let Some(provider) = self.edit_prediction_provider() {
 7456                    provider.accept(cx);
 7457                }
 7458
 7459                // Store the transaction ID and selections before applying the edit
 7460                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7461
 7462                let snapshot = self.buffer.read(cx).snapshot(cx);
 7463                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7464
 7465                self.buffer.update(cx, |buffer, cx| {
 7466                    buffer.edit(edits.iter().cloned(), None, cx)
 7467                });
 7468
 7469                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7470                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7471                });
 7472
 7473                let selections = self.selections.disjoint_anchors_arc();
 7474                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7475                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7476                    if has_new_transaction {
 7477                        self.selection_history
 7478                            .insert_transaction(transaction_id_now, selections);
 7479                    }
 7480                }
 7481
 7482                self.update_visible_edit_prediction(window, cx);
 7483                if self.active_edit_prediction.is_none() {
 7484                    self.refresh_edit_prediction(true, true, window, cx);
 7485                }
 7486
 7487                cx.notify();
 7488            }
 7489        }
 7490
 7491        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7492    }
 7493
 7494    pub fn accept_partial_edit_prediction(
 7495        &mut self,
 7496        _: &AcceptPartialEditPrediction,
 7497        window: &mut Window,
 7498        cx: &mut Context<Self>,
 7499    ) {
 7500        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7501            return;
 7502        };
 7503        if self.selections.count() != 1 {
 7504            return;
 7505        }
 7506
 7507        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7508
 7509        match &active_edit_prediction.completion {
 7510            EditPrediction::Move { target, .. } => {
 7511                let target = *target;
 7512                self.change_selections(
 7513                    SelectionEffects::scroll(Autoscroll::newest()),
 7514                    window,
 7515                    cx,
 7516                    |selections| {
 7517                        selections.select_anchor_ranges([target..target]);
 7518                    },
 7519                );
 7520            }
 7521            EditPrediction::Edit { edits, .. } => {
 7522                // Find an insertion that starts at the cursor position.
 7523                let snapshot = self.buffer.read(cx).snapshot(cx);
 7524                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7525                let insertion = edits.iter().find_map(|(range, text)| {
 7526                    let range = range.to_offset(&snapshot);
 7527                    if range.is_empty() && range.start == cursor_offset {
 7528                        Some(text)
 7529                    } else {
 7530                        None
 7531                    }
 7532                });
 7533
 7534                if let Some(text) = insertion {
 7535                    let mut partial_completion = text
 7536                        .chars()
 7537                        .by_ref()
 7538                        .take_while(|c| c.is_alphabetic())
 7539                        .collect::<String>();
 7540                    if partial_completion.is_empty() {
 7541                        partial_completion = text
 7542                            .chars()
 7543                            .by_ref()
 7544                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7545                            .collect::<String>();
 7546                    }
 7547
 7548                    cx.emit(EditorEvent::InputHandled {
 7549                        utf16_range_to_replace: None,
 7550                        text: partial_completion.clone().into(),
 7551                    });
 7552
 7553                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7554
 7555                    self.refresh_edit_prediction(true, true, window, cx);
 7556                    cx.notify();
 7557                } else {
 7558                    self.accept_edit_prediction(&Default::default(), window, cx);
 7559                }
 7560            }
 7561        }
 7562    }
 7563
 7564    fn discard_edit_prediction(
 7565        &mut self,
 7566        should_report_edit_prediction_event: bool,
 7567        cx: &mut Context<Self>,
 7568    ) -> bool {
 7569        if should_report_edit_prediction_event {
 7570            let completion_id = self
 7571                .active_edit_prediction
 7572                .as_ref()
 7573                .and_then(|active_completion| active_completion.completion_id.clone());
 7574
 7575            self.report_edit_prediction_event(completion_id, false, cx);
 7576        }
 7577
 7578        if let Some(provider) = self.edit_prediction_provider() {
 7579            provider.discard(cx);
 7580        }
 7581
 7582        self.take_active_edit_prediction(cx)
 7583    }
 7584
 7585    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7586        let Some(provider) = self.edit_prediction_provider() else {
 7587            return;
 7588        };
 7589
 7590        let Some((_, buffer, _)) = self
 7591            .buffer
 7592            .read(cx)
 7593            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7594        else {
 7595            return;
 7596        };
 7597
 7598        let extension = buffer
 7599            .read(cx)
 7600            .file()
 7601            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7602
 7603        let event_type = match accepted {
 7604            true => "Edit Prediction Accepted",
 7605            false => "Edit Prediction Discarded",
 7606        };
 7607        telemetry::event!(
 7608            event_type,
 7609            provider = provider.name(),
 7610            prediction_id = id,
 7611            suggestion_accepted = accepted,
 7612            file_extension = extension,
 7613        );
 7614    }
 7615
 7616    pub fn has_active_edit_prediction(&self) -> bool {
 7617        self.active_edit_prediction.is_some()
 7618    }
 7619
 7620    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7621        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7622            return false;
 7623        };
 7624
 7625        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7626        self.clear_highlights::<EditPredictionHighlight>(cx);
 7627        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7628        true
 7629    }
 7630
 7631    /// Returns true when we're displaying the edit prediction popover below the cursor
 7632    /// like we are not previewing and the LSP autocomplete menu is visible
 7633    /// or we are in `when_holding_modifier` mode.
 7634    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7635        if self.edit_prediction_preview_is_active()
 7636            || !self.show_edit_predictions_in_menu()
 7637            || !self.edit_predictions_enabled()
 7638        {
 7639            return false;
 7640        }
 7641
 7642        if self.has_visible_completions_menu() {
 7643            return true;
 7644        }
 7645
 7646        has_completion && self.edit_prediction_requires_modifier()
 7647    }
 7648
 7649    fn handle_modifiers_changed(
 7650        &mut self,
 7651        modifiers: Modifiers,
 7652        position_map: &PositionMap,
 7653        window: &mut Window,
 7654        cx: &mut Context<Self>,
 7655    ) {
 7656        if self.show_edit_predictions_in_menu() {
 7657            self.update_edit_prediction_preview(&modifiers, window, cx);
 7658        }
 7659
 7660        self.update_selection_mode(&modifiers, position_map, window, cx);
 7661
 7662        let mouse_position = window.mouse_position();
 7663        if !position_map.text_hitbox.is_hovered(window) {
 7664            return;
 7665        }
 7666
 7667        self.update_hovered_link(
 7668            position_map.point_for_position(mouse_position),
 7669            &position_map.snapshot,
 7670            modifiers,
 7671            window,
 7672            cx,
 7673        )
 7674    }
 7675
 7676    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7677        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7678        if invert {
 7679            match multi_cursor_setting {
 7680                MultiCursorModifier::Alt => modifiers.alt,
 7681                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7682            }
 7683        } else {
 7684            match multi_cursor_setting {
 7685                MultiCursorModifier::Alt => modifiers.secondary(),
 7686                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7687            }
 7688        }
 7689    }
 7690
 7691    fn columnar_selection_mode(
 7692        modifiers: &Modifiers,
 7693        cx: &mut Context<Self>,
 7694    ) -> Option<ColumnarMode> {
 7695        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7696            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7697                Some(ColumnarMode::FromMouse)
 7698            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7699                Some(ColumnarMode::FromSelection)
 7700            } else {
 7701                None
 7702            }
 7703        } else {
 7704            None
 7705        }
 7706    }
 7707
 7708    fn update_selection_mode(
 7709        &mut self,
 7710        modifiers: &Modifiers,
 7711        position_map: &PositionMap,
 7712        window: &mut Window,
 7713        cx: &mut Context<Self>,
 7714    ) {
 7715        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7716            return;
 7717        };
 7718        if self.selections.pending_anchor().is_none() {
 7719            return;
 7720        }
 7721
 7722        let mouse_position = window.mouse_position();
 7723        let point_for_position = position_map.point_for_position(mouse_position);
 7724        let position = point_for_position.previous_valid;
 7725
 7726        self.select(
 7727            SelectPhase::BeginColumnar {
 7728                position,
 7729                reset: false,
 7730                mode,
 7731                goal_column: point_for_position.exact_unclipped.column(),
 7732            },
 7733            window,
 7734            cx,
 7735        );
 7736    }
 7737
 7738    fn update_edit_prediction_preview(
 7739        &mut self,
 7740        modifiers: &Modifiers,
 7741        window: &mut Window,
 7742        cx: &mut Context<Self>,
 7743    ) {
 7744        let mut modifiers_held = false;
 7745        if let Some(accept_keystroke) = self
 7746            .accept_edit_prediction_keybind(false, window, cx)
 7747            .keystroke()
 7748        {
 7749            modifiers_held = modifiers_held
 7750                || (accept_keystroke.modifiers() == modifiers
 7751                    && accept_keystroke.modifiers().modified());
 7752        };
 7753        if let Some(accept_partial_keystroke) = self
 7754            .accept_edit_prediction_keybind(true, window, cx)
 7755            .keystroke()
 7756        {
 7757            modifiers_held = modifiers_held
 7758                || (accept_partial_keystroke.modifiers() == modifiers
 7759                    && accept_partial_keystroke.modifiers().modified());
 7760        }
 7761
 7762        if modifiers_held {
 7763            if matches!(
 7764                self.edit_prediction_preview,
 7765                EditPredictionPreview::Inactive { .. }
 7766            ) {
 7767                self.edit_prediction_preview = EditPredictionPreview::Active {
 7768                    previous_scroll_position: None,
 7769                    since: Instant::now(),
 7770                };
 7771
 7772                self.update_visible_edit_prediction(window, cx);
 7773                cx.notify();
 7774            }
 7775        } else if let EditPredictionPreview::Active {
 7776            previous_scroll_position,
 7777            since,
 7778        } = self.edit_prediction_preview
 7779        {
 7780            if let (Some(previous_scroll_position), Some(position_map)) =
 7781                (previous_scroll_position, self.last_position_map.as_ref())
 7782            {
 7783                self.set_scroll_position(
 7784                    previous_scroll_position
 7785                        .scroll_position(&position_map.snapshot.display_snapshot),
 7786                    window,
 7787                    cx,
 7788                );
 7789            }
 7790
 7791            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7792                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7793            };
 7794            self.clear_row_highlights::<EditPredictionPreview>();
 7795            self.update_visible_edit_prediction(window, cx);
 7796            cx.notify();
 7797        }
 7798    }
 7799
 7800    fn update_visible_edit_prediction(
 7801        &mut self,
 7802        _window: &mut Window,
 7803        cx: &mut Context<Self>,
 7804    ) -> Option<()> {
 7805        if DisableAiSettings::get_global(cx).disable_ai {
 7806            return None;
 7807        }
 7808
 7809        if self.ime_transaction.is_some() {
 7810            self.discard_edit_prediction(false, cx);
 7811            return None;
 7812        }
 7813
 7814        let selection = self.selections.newest_anchor();
 7815        let cursor = selection.head();
 7816        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7817        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7818        let excerpt_id = cursor.excerpt_id;
 7819
 7820        let show_in_menu = self.show_edit_predictions_in_menu();
 7821        let completions_menu_has_precedence = !show_in_menu
 7822            && (self.context_menu.borrow().is_some()
 7823                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7824
 7825        if completions_menu_has_precedence
 7826            || !offset_selection.is_empty()
 7827            || self
 7828                .active_edit_prediction
 7829                .as_ref()
 7830                .is_some_and(|completion| {
 7831                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7832                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7833                    !invalidation_range.contains(&offset_selection.head())
 7834                })
 7835        {
 7836            self.discard_edit_prediction(false, cx);
 7837            return None;
 7838        }
 7839
 7840        self.take_active_edit_prediction(cx);
 7841        let Some(provider) = self.edit_prediction_provider() else {
 7842            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7843            return None;
 7844        };
 7845
 7846        let (buffer, cursor_buffer_position) =
 7847            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7848
 7849        self.edit_prediction_settings =
 7850            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7851
 7852        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7853            self.discard_edit_prediction(false, cx);
 7854            return None;
 7855        };
 7856
 7857        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7858
 7859        if self.edit_prediction_indent_conflict {
 7860            let cursor_point = cursor.to_point(&multibuffer);
 7861
 7862            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7863
 7864            if let Some((_, indent)) = indents.iter().next()
 7865                && indent.len == cursor_point.column
 7866            {
 7867                self.edit_prediction_indent_conflict = false;
 7868            }
 7869        }
 7870
 7871        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7872        let edits = edit_prediction
 7873            .edits
 7874            .into_iter()
 7875            .flat_map(|(range, new_text)| {
 7876                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7877                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7878                Some((start..end, new_text))
 7879            })
 7880            .collect::<Vec<_>>();
 7881        if edits.is_empty() {
 7882            return None;
 7883        }
 7884
 7885        let first_edit_start = edits.first().unwrap().0.start;
 7886        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7887        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7888
 7889        let last_edit_end = edits.last().unwrap().0.end;
 7890        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7891        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7892
 7893        let cursor_row = cursor.to_point(&multibuffer).row;
 7894
 7895        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7896
 7897        let mut inlay_ids = Vec::new();
 7898        let invalidation_row_range;
 7899        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7900            Some(cursor_row..edit_end_row)
 7901        } else if cursor_row > edit_end_row {
 7902            Some(edit_start_row..cursor_row)
 7903        } else {
 7904            None
 7905        };
 7906        let supports_jump = self
 7907            .edit_prediction_provider
 7908            .as_ref()
 7909            .map(|provider| provider.provider.supports_jump_to_edit())
 7910            .unwrap_or(true);
 7911
 7912        let is_move = supports_jump
 7913            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7914        let completion = if is_move {
 7915            invalidation_row_range =
 7916                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7917            let target = first_edit_start;
 7918            EditPrediction::Move { target, snapshot }
 7919        } else {
 7920            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7921                && !self.edit_predictions_hidden_for_vim_mode;
 7922
 7923            if show_completions_in_buffer {
 7924                if edits
 7925                    .iter()
 7926                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7927                {
 7928                    let mut inlays = Vec::new();
 7929                    for (range, new_text) in &edits {
 7930                        let inlay = Inlay::edit_prediction(
 7931                            post_inc(&mut self.next_inlay_id),
 7932                            range.start,
 7933                            new_text.as_str(),
 7934                        );
 7935                        inlay_ids.push(inlay.id);
 7936                        inlays.push(inlay);
 7937                    }
 7938
 7939                    self.splice_inlays(&[], inlays, cx);
 7940                } else {
 7941                    let background_color = cx.theme().status().deleted_background;
 7942                    self.highlight_text::<EditPredictionHighlight>(
 7943                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7944                        HighlightStyle {
 7945                            background_color: Some(background_color),
 7946                            ..Default::default()
 7947                        },
 7948                        cx,
 7949                    );
 7950                }
 7951            }
 7952
 7953            invalidation_row_range = edit_start_row..edit_end_row;
 7954
 7955            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7956                if provider.show_tab_accept_marker() {
 7957                    EditDisplayMode::TabAccept
 7958                } else {
 7959                    EditDisplayMode::Inline
 7960                }
 7961            } else {
 7962                EditDisplayMode::DiffPopover
 7963            };
 7964
 7965            EditPrediction::Edit {
 7966                edits,
 7967                edit_preview: edit_prediction.edit_preview,
 7968                display_mode,
 7969                snapshot,
 7970            }
 7971        };
 7972
 7973        let invalidation_range = multibuffer
 7974            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7975            ..multibuffer.anchor_after(Point::new(
 7976                invalidation_row_range.end,
 7977                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7978            ));
 7979
 7980        self.stale_edit_prediction_in_menu = None;
 7981        self.active_edit_prediction = Some(EditPredictionState {
 7982            inlay_ids,
 7983            completion,
 7984            completion_id: edit_prediction.id,
 7985            invalidation_range,
 7986        });
 7987
 7988        cx.notify();
 7989
 7990        Some(())
 7991    }
 7992
 7993    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7994        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7995    }
 7996
 7997    fn clear_tasks(&mut self) {
 7998        self.tasks.clear()
 7999    }
 8000
 8001    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8002        if self.tasks.insert(key, value).is_some() {
 8003            // This case should hopefully be rare, but just in case...
 8004            log::error!(
 8005                "multiple different run targets found on a single line, only the last target will be rendered"
 8006            )
 8007        }
 8008    }
 8009
 8010    /// Get all display points of breakpoints that will be rendered within editor
 8011    ///
 8012    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8013    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8014    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8015    fn active_breakpoints(
 8016        &self,
 8017        range: Range<DisplayRow>,
 8018        window: &mut Window,
 8019        cx: &mut Context<Self>,
 8020    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8021        let mut breakpoint_display_points = HashMap::default();
 8022
 8023        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8024            return breakpoint_display_points;
 8025        };
 8026
 8027        let snapshot = self.snapshot(window, cx);
 8028
 8029        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8030        let Some(project) = self.project() else {
 8031            return breakpoint_display_points;
 8032        };
 8033
 8034        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8035            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8036
 8037        for (buffer_snapshot, range, excerpt_id) in
 8038            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8039        {
 8040            let Some(buffer) = project
 8041                .read(cx)
 8042                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8043            else {
 8044                continue;
 8045            };
 8046            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8047                &buffer,
 8048                Some(
 8049                    buffer_snapshot.anchor_before(range.start)
 8050                        ..buffer_snapshot.anchor_after(range.end),
 8051                ),
 8052                buffer_snapshot,
 8053                cx,
 8054            );
 8055            for (breakpoint, state) in breakpoints {
 8056                let multi_buffer_anchor =
 8057                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8058                let position = multi_buffer_anchor
 8059                    .to_point(multi_buffer_snapshot)
 8060                    .to_display_point(&snapshot);
 8061
 8062                breakpoint_display_points.insert(
 8063                    position.row(),
 8064                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8065                );
 8066            }
 8067        }
 8068
 8069        breakpoint_display_points
 8070    }
 8071
 8072    fn breakpoint_context_menu(
 8073        &self,
 8074        anchor: Anchor,
 8075        window: &mut Window,
 8076        cx: &mut Context<Self>,
 8077    ) -> Entity<ui::ContextMenu> {
 8078        let weak_editor = cx.weak_entity();
 8079        let focus_handle = self.focus_handle(cx);
 8080
 8081        let row = self
 8082            .buffer
 8083            .read(cx)
 8084            .snapshot(cx)
 8085            .summary_for_anchor::<Point>(&anchor)
 8086            .row;
 8087
 8088        let breakpoint = self
 8089            .breakpoint_at_row(row, window, cx)
 8090            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8091
 8092        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8093            "Edit Log Breakpoint"
 8094        } else {
 8095            "Set Log Breakpoint"
 8096        };
 8097
 8098        let condition_breakpoint_msg = if breakpoint
 8099            .as_ref()
 8100            .is_some_and(|bp| bp.1.condition.is_some())
 8101        {
 8102            "Edit Condition Breakpoint"
 8103        } else {
 8104            "Set Condition Breakpoint"
 8105        };
 8106
 8107        let hit_condition_breakpoint_msg = if breakpoint
 8108            .as_ref()
 8109            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8110        {
 8111            "Edit Hit Condition Breakpoint"
 8112        } else {
 8113            "Set Hit Condition Breakpoint"
 8114        };
 8115
 8116        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8117            "Unset Breakpoint"
 8118        } else {
 8119            "Set Breakpoint"
 8120        };
 8121
 8122        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8123
 8124        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8125            BreakpointState::Enabled => Some("Disable"),
 8126            BreakpointState::Disabled => Some("Enable"),
 8127        });
 8128
 8129        let (anchor, breakpoint) =
 8130            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8131
 8132        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8133            menu.on_blur_subscription(Subscription::new(|| {}))
 8134                .context(focus_handle)
 8135                .when(run_to_cursor, |this| {
 8136                    let weak_editor = weak_editor.clone();
 8137                    this.entry("Run to cursor", None, move |window, cx| {
 8138                        weak_editor
 8139                            .update(cx, |editor, cx| {
 8140                                editor.change_selections(
 8141                                    SelectionEffects::no_scroll(),
 8142                                    window,
 8143                                    cx,
 8144                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8145                                );
 8146                            })
 8147                            .ok();
 8148
 8149                        window.dispatch_action(Box::new(RunToCursor), cx);
 8150                    })
 8151                    .separator()
 8152                })
 8153                .when_some(toggle_state_msg, |this, msg| {
 8154                    this.entry(msg, None, {
 8155                        let weak_editor = weak_editor.clone();
 8156                        let breakpoint = breakpoint.clone();
 8157                        move |_window, cx| {
 8158                            weak_editor
 8159                                .update(cx, |this, cx| {
 8160                                    this.edit_breakpoint_at_anchor(
 8161                                        anchor,
 8162                                        breakpoint.as_ref().clone(),
 8163                                        BreakpointEditAction::InvertState,
 8164                                        cx,
 8165                                    );
 8166                                })
 8167                                .log_err();
 8168                        }
 8169                    })
 8170                })
 8171                .entry(set_breakpoint_msg, None, {
 8172                    let weak_editor = weak_editor.clone();
 8173                    let breakpoint = breakpoint.clone();
 8174                    move |_window, cx| {
 8175                        weak_editor
 8176                            .update(cx, |this, cx| {
 8177                                this.edit_breakpoint_at_anchor(
 8178                                    anchor,
 8179                                    breakpoint.as_ref().clone(),
 8180                                    BreakpointEditAction::Toggle,
 8181                                    cx,
 8182                                );
 8183                            })
 8184                            .log_err();
 8185                    }
 8186                })
 8187                .entry(log_breakpoint_msg, None, {
 8188                    let breakpoint = breakpoint.clone();
 8189                    let weak_editor = weak_editor.clone();
 8190                    move |window, cx| {
 8191                        weak_editor
 8192                            .update(cx, |this, cx| {
 8193                                this.add_edit_breakpoint_block(
 8194                                    anchor,
 8195                                    breakpoint.as_ref(),
 8196                                    BreakpointPromptEditAction::Log,
 8197                                    window,
 8198                                    cx,
 8199                                );
 8200                            })
 8201                            .log_err();
 8202                    }
 8203                })
 8204                .entry(condition_breakpoint_msg, None, {
 8205                    let breakpoint = breakpoint.clone();
 8206                    let weak_editor = weak_editor.clone();
 8207                    move |window, cx| {
 8208                        weak_editor
 8209                            .update(cx, |this, cx| {
 8210                                this.add_edit_breakpoint_block(
 8211                                    anchor,
 8212                                    breakpoint.as_ref(),
 8213                                    BreakpointPromptEditAction::Condition,
 8214                                    window,
 8215                                    cx,
 8216                                );
 8217                            })
 8218                            .log_err();
 8219                    }
 8220                })
 8221                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8222                    weak_editor
 8223                        .update(cx, |this, cx| {
 8224                            this.add_edit_breakpoint_block(
 8225                                anchor,
 8226                                breakpoint.as_ref(),
 8227                                BreakpointPromptEditAction::HitCondition,
 8228                                window,
 8229                                cx,
 8230                            );
 8231                        })
 8232                        .log_err();
 8233                })
 8234        })
 8235    }
 8236
 8237    fn render_breakpoint(
 8238        &self,
 8239        position: Anchor,
 8240        row: DisplayRow,
 8241        breakpoint: &Breakpoint,
 8242        state: Option<BreakpointSessionState>,
 8243        cx: &mut Context<Self>,
 8244    ) -> IconButton {
 8245        let is_rejected = state.is_some_and(|s| !s.verified);
 8246        // Is it a breakpoint that shows up when hovering over gutter?
 8247        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8248            (false, false),
 8249            |PhantomBreakpointIndicator {
 8250                 is_active,
 8251                 display_row,
 8252                 collides_with_existing_breakpoint,
 8253             }| {
 8254                (
 8255                    is_active && display_row == row,
 8256                    collides_with_existing_breakpoint,
 8257                )
 8258            },
 8259        );
 8260
 8261        let (color, icon) = {
 8262            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8263                (false, false) => ui::IconName::DebugBreakpoint,
 8264                (true, false) => ui::IconName::DebugLogBreakpoint,
 8265                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8266                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8267            };
 8268
 8269            let color = if is_phantom {
 8270                Color::Hint
 8271            } else if is_rejected {
 8272                Color::Disabled
 8273            } else {
 8274                Color::Debugger
 8275            };
 8276
 8277            (color, icon)
 8278        };
 8279
 8280        let breakpoint = Arc::from(breakpoint.clone());
 8281
 8282        let alt_as_text = gpui::Keystroke {
 8283            modifiers: Modifiers::secondary_key(),
 8284            ..Default::default()
 8285        };
 8286        let primary_action_text = if breakpoint.is_disabled() {
 8287            "Enable breakpoint"
 8288        } else if is_phantom && !collides_with_existing {
 8289            "Set breakpoint"
 8290        } else {
 8291            "Unset breakpoint"
 8292        };
 8293        let focus_handle = self.focus_handle.clone();
 8294
 8295        let meta = if is_rejected {
 8296            SharedString::from("No executable code is associated with this line.")
 8297        } else if collides_with_existing && !breakpoint.is_disabled() {
 8298            SharedString::from(format!(
 8299                "{alt_as_text}-click to disable,\nright-click for more options."
 8300            ))
 8301        } else {
 8302            SharedString::from("Right-click for more options.")
 8303        };
 8304        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8305            .icon_size(IconSize::XSmall)
 8306            .size(ui::ButtonSize::None)
 8307            .when(is_rejected, |this| {
 8308                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8309            })
 8310            .icon_color(color)
 8311            .style(ButtonStyle::Transparent)
 8312            .on_click(cx.listener({
 8313                move |editor, event: &ClickEvent, window, cx| {
 8314                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8315                        BreakpointEditAction::InvertState
 8316                    } else {
 8317                        BreakpointEditAction::Toggle
 8318                    };
 8319
 8320                    window.focus(&editor.focus_handle(cx));
 8321                    editor.edit_breakpoint_at_anchor(
 8322                        position,
 8323                        breakpoint.as_ref().clone(),
 8324                        edit_action,
 8325                        cx,
 8326                    );
 8327                }
 8328            }))
 8329            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8330                editor.set_breakpoint_context_menu(
 8331                    row,
 8332                    Some(position),
 8333                    event.position(),
 8334                    window,
 8335                    cx,
 8336                );
 8337            }))
 8338            .tooltip(move |window, cx| {
 8339                Tooltip::with_meta_in(
 8340                    primary_action_text,
 8341                    Some(&ToggleBreakpoint),
 8342                    meta.clone(),
 8343                    &focus_handle,
 8344                    window,
 8345                    cx,
 8346                )
 8347            })
 8348    }
 8349
 8350    fn build_tasks_context(
 8351        project: &Entity<Project>,
 8352        buffer: &Entity<Buffer>,
 8353        buffer_row: u32,
 8354        tasks: &Arc<RunnableTasks>,
 8355        cx: &mut Context<Self>,
 8356    ) -> Task<Option<task::TaskContext>> {
 8357        let position = Point::new(buffer_row, tasks.column);
 8358        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8359        let location = Location {
 8360            buffer: buffer.clone(),
 8361            range: range_start..range_start,
 8362        };
 8363        // Fill in the environmental variables from the tree-sitter captures
 8364        let mut captured_task_variables = TaskVariables::default();
 8365        for (capture_name, value) in tasks.extra_variables.clone() {
 8366            captured_task_variables.insert(
 8367                task::VariableName::Custom(capture_name.into()),
 8368                value.clone(),
 8369            );
 8370        }
 8371        project.update(cx, |project, cx| {
 8372            project.task_store().update(cx, |task_store, cx| {
 8373                task_store.task_context_for_location(captured_task_variables, location, cx)
 8374            })
 8375        })
 8376    }
 8377
 8378    pub fn spawn_nearest_task(
 8379        &mut self,
 8380        action: &SpawnNearestTask,
 8381        window: &mut Window,
 8382        cx: &mut Context<Self>,
 8383    ) {
 8384        let Some((workspace, _)) = self.workspace.clone() else {
 8385            return;
 8386        };
 8387        let Some(project) = self.project.clone() else {
 8388            return;
 8389        };
 8390
 8391        // Try to find a closest, enclosing node using tree-sitter that has a task
 8392        let Some((buffer, buffer_row, tasks)) = self
 8393            .find_enclosing_node_task(cx)
 8394            // Or find the task that's closest in row-distance.
 8395            .or_else(|| self.find_closest_task(cx))
 8396        else {
 8397            return;
 8398        };
 8399
 8400        let reveal_strategy = action.reveal;
 8401        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8402        cx.spawn_in(window, async move |_, cx| {
 8403            let context = task_context.await?;
 8404            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8405
 8406            let resolved = &mut resolved_task.resolved;
 8407            resolved.reveal = reveal_strategy;
 8408
 8409            workspace
 8410                .update_in(cx, |workspace, window, cx| {
 8411                    workspace.schedule_resolved_task(
 8412                        task_source_kind,
 8413                        resolved_task,
 8414                        false,
 8415                        window,
 8416                        cx,
 8417                    );
 8418                })
 8419                .ok()
 8420        })
 8421        .detach();
 8422    }
 8423
 8424    fn find_closest_task(
 8425        &mut self,
 8426        cx: &mut Context<Self>,
 8427    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8428        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8429
 8430        let ((buffer_id, row), tasks) = self
 8431            .tasks
 8432            .iter()
 8433            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8434
 8435        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8436        let tasks = Arc::new(tasks.to_owned());
 8437        Some((buffer, *row, tasks))
 8438    }
 8439
 8440    fn find_enclosing_node_task(
 8441        &mut self,
 8442        cx: &mut Context<Self>,
 8443    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8444        let snapshot = self.buffer.read(cx).snapshot(cx);
 8445        let offset = self.selections.newest::<usize>(cx).head();
 8446        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8447        let buffer_id = excerpt.buffer().remote_id();
 8448
 8449        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8450        let mut cursor = layer.node().walk();
 8451
 8452        while cursor.goto_first_child_for_byte(offset).is_some() {
 8453            if cursor.node().end_byte() == offset {
 8454                cursor.goto_next_sibling();
 8455            }
 8456        }
 8457
 8458        // Ascend to the smallest ancestor that contains the range and has a task.
 8459        loop {
 8460            let node = cursor.node();
 8461            let node_range = node.byte_range();
 8462            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8463
 8464            // Check if this node contains our offset
 8465            if node_range.start <= offset && node_range.end >= offset {
 8466                // If it contains offset, check for task
 8467                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8468                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8469                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8470                }
 8471            }
 8472
 8473            if !cursor.goto_parent() {
 8474                break;
 8475            }
 8476        }
 8477        None
 8478    }
 8479
 8480    fn render_run_indicator(
 8481        &self,
 8482        _style: &EditorStyle,
 8483        is_active: bool,
 8484        row: DisplayRow,
 8485        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8486        cx: &mut Context<Self>,
 8487    ) -> IconButton {
 8488        let color = Color::Muted;
 8489        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8490
 8491        IconButton::new(
 8492            ("run_indicator", row.0 as usize),
 8493            ui::IconName::PlayOutlined,
 8494        )
 8495        .shape(ui::IconButtonShape::Square)
 8496        .icon_size(IconSize::XSmall)
 8497        .icon_color(color)
 8498        .toggle_state(is_active)
 8499        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8500            let quick_launch = match e {
 8501                ClickEvent::Keyboard(_) => true,
 8502                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8503            };
 8504
 8505            window.focus(&editor.focus_handle(cx));
 8506            editor.toggle_code_actions(
 8507                &ToggleCodeActions {
 8508                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8509                    quick_launch,
 8510                },
 8511                window,
 8512                cx,
 8513            );
 8514        }))
 8515        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8516            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8517        }))
 8518    }
 8519
 8520    pub fn context_menu_visible(&self) -> bool {
 8521        !self.edit_prediction_preview_is_active()
 8522            && self
 8523                .context_menu
 8524                .borrow()
 8525                .as_ref()
 8526                .is_some_and(|menu| menu.visible())
 8527    }
 8528
 8529    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8530        self.context_menu
 8531            .borrow()
 8532            .as_ref()
 8533            .map(|menu| menu.origin())
 8534    }
 8535
 8536    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8537        self.context_menu_options = Some(options);
 8538    }
 8539
 8540    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8541    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8542
 8543    fn render_edit_prediction_popover(
 8544        &mut self,
 8545        text_bounds: &Bounds<Pixels>,
 8546        content_origin: gpui::Point<Pixels>,
 8547        right_margin: Pixels,
 8548        editor_snapshot: &EditorSnapshot,
 8549        visible_row_range: Range<DisplayRow>,
 8550        scroll_top: f32,
 8551        scroll_bottom: f32,
 8552        line_layouts: &[LineWithInvisibles],
 8553        line_height: Pixels,
 8554        scroll_pixel_position: gpui::Point<Pixels>,
 8555        newest_selection_head: Option<DisplayPoint>,
 8556        editor_width: Pixels,
 8557        style: &EditorStyle,
 8558        window: &mut Window,
 8559        cx: &mut App,
 8560    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8561        if self.mode().is_minimap() {
 8562            return None;
 8563        }
 8564        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8565
 8566        if self.edit_prediction_visible_in_cursor_popover(true) {
 8567            return None;
 8568        }
 8569
 8570        match &active_edit_prediction.completion {
 8571            EditPrediction::Move { target, .. } => {
 8572                let target_display_point = target.to_display_point(editor_snapshot);
 8573
 8574                if self.edit_prediction_requires_modifier() {
 8575                    if !self.edit_prediction_preview_is_active() {
 8576                        return None;
 8577                    }
 8578
 8579                    self.render_edit_prediction_modifier_jump_popover(
 8580                        text_bounds,
 8581                        content_origin,
 8582                        visible_row_range,
 8583                        line_layouts,
 8584                        line_height,
 8585                        scroll_pixel_position,
 8586                        newest_selection_head,
 8587                        target_display_point,
 8588                        window,
 8589                        cx,
 8590                    )
 8591                } else {
 8592                    self.render_edit_prediction_eager_jump_popover(
 8593                        text_bounds,
 8594                        content_origin,
 8595                        editor_snapshot,
 8596                        visible_row_range,
 8597                        scroll_top,
 8598                        scroll_bottom,
 8599                        line_height,
 8600                        scroll_pixel_position,
 8601                        target_display_point,
 8602                        editor_width,
 8603                        window,
 8604                        cx,
 8605                    )
 8606                }
 8607            }
 8608            EditPrediction::Edit {
 8609                display_mode: EditDisplayMode::Inline,
 8610                ..
 8611            } => None,
 8612            EditPrediction::Edit {
 8613                display_mode: EditDisplayMode::TabAccept,
 8614                edits,
 8615                ..
 8616            } => {
 8617                let range = &edits.first()?.0;
 8618                let target_display_point = range.end.to_display_point(editor_snapshot);
 8619
 8620                self.render_edit_prediction_end_of_line_popover(
 8621                    "Accept",
 8622                    editor_snapshot,
 8623                    visible_row_range,
 8624                    target_display_point,
 8625                    line_height,
 8626                    scroll_pixel_position,
 8627                    content_origin,
 8628                    editor_width,
 8629                    window,
 8630                    cx,
 8631                )
 8632            }
 8633            EditPrediction::Edit {
 8634                edits,
 8635                edit_preview,
 8636                display_mode: EditDisplayMode::DiffPopover,
 8637                snapshot,
 8638            } => self.render_edit_prediction_diff_popover(
 8639                text_bounds,
 8640                content_origin,
 8641                right_margin,
 8642                editor_snapshot,
 8643                visible_row_range,
 8644                line_layouts,
 8645                line_height,
 8646                scroll_pixel_position,
 8647                newest_selection_head,
 8648                editor_width,
 8649                style,
 8650                edits,
 8651                edit_preview,
 8652                snapshot,
 8653                window,
 8654                cx,
 8655            ),
 8656        }
 8657    }
 8658
 8659    fn render_edit_prediction_modifier_jump_popover(
 8660        &mut self,
 8661        text_bounds: &Bounds<Pixels>,
 8662        content_origin: gpui::Point<Pixels>,
 8663        visible_row_range: Range<DisplayRow>,
 8664        line_layouts: &[LineWithInvisibles],
 8665        line_height: Pixels,
 8666        scroll_pixel_position: gpui::Point<Pixels>,
 8667        newest_selection_head: Option<DisplayPoint>,
 8668        target_display_point: DisplayPoint,
 8669        window: &mut Window,
 8670        cx: &mut App,
 8671    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8672        let scrolled_content_origin =
 8673            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8674
 8675        const SCROLL_PADDING_Y: Pixels = px(12.);
 8676
 8677        if target_display_point.row() < visible_row_range.start {
 8678            return self.render_edit_prediction_scroll_popover(
 8679                |_| SCROLL_PADDING_Y,
 8680                IconName::ArrowUp,
 8681                visible_row_range,
 8682                line_layouts,
 8683                newest_selection_head,
 8684                scrolled_content_origin,
 8685                window,
 8686                cx,
 8687            );
 8688        } else if target_display_point.row() >= visible_row_range.end {
 8689            return self.render_edit_prediction_scroll_popover(
 8690                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8691                IconName::ArrowDown,
 8692                visible_row_range,
 8693                line_layouts,
 8694                newest_selection_head,
 8695                scrolled_content_origin,
 8696                window,
 8697                cx,
 8698            );
 8699        }
 8700
 8701        const POLE_WIDTH: Pixels = px(2.);
 8702
 8703        let line_layout =
 8704            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8705        let target_column = target_display_point.column() as usize;
 8706
 8707        let target_x = line_layout.x_for_index(target_column);
 8708        let target_y =
 8709            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8710
 8711        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8712
 8713        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8714        border_color.l += 0.001;
 8715
 8716        let mut element = v_flex()
 8717            .items_end()
 8718            .when(flag_on_right, |el| el.items_start())
 8719            .child(if flag_on_right {
 8720                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8721                    .rounded_bl(px(0.))
 8722                    .rounded_tl(px(0.))
 8723                    .border_l_2()
 8724                    .border_color(border_color)
 8725            } else {
 8726                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8727                    .rounded_br(px(0.))
 8728                    .rounded_tr(px(0.))
 8729                    .border_r_2()
 8730                    .border_color(border_color)
 8731            })
 8732            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8733            .into_any();
 8734
 8735        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8736
 8737        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8738            - point(
 8739                if flag_on_right {
 8740                    POLE_WIDTH
 8741                } else {
 8742                    size.width - POLE_WIDTH
 8743                },
 8744                size.height - line_height,
 8745            );
 8746
 8747        origin.x = origin.x.max(content_origin.x);
 8748
 8749        element.prepaint_at(origin, window, cx);
 8750
 8751        Some((element, origin))
 8752    }
 8753
 8754    fn render_edit_prediction_scroll_popover(
 8755        &mut self,
 8756        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8757        scroll_icon: IconName,
 8758        visible_row_range: Range<DisplayRow>,
 8759        line_layouts: &[LineWithInvisibles],
 8760        newest_selection_head: Option<DisplayPoint>,
 8761        scrolled_content_origin: gpui::Point<Pixels>,
 8762        window: &mut Window,
 8763        cx: &mut App,
 8764    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8765        let mut element = self
 8766            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8767            .into_any();
 8768
 8769        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8770
 8771        let cursor = newest_selection_head?;
 8772        let cursor_row_layout =
 8773            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8774        let cursor_column = cursor.column() as usize;
 8775
 8776        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8777
 8778        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8779
 8780        element.prepaint_at(origin, window, cx);
 8781        Some((element, origin))
 8782    }
 8783
 8784    fn render_edit_prediction_eager_jump_popover(
 8785        &mut self,
 8786        text_bounds: &Bounds<Pixels>,
 8787        content_origin: gpui::Point<Pixels>,
 8788        editor_snapshot: &EditorSnapshot,
 8789        visible_row_range: Range<DisplayRow>,
 8790        scroll_top: f32,
 8791        scroll_bottom: f32,
 8792        line_height: Pixels,
 8793        scroll_pixel_position: gpui::Point<Pixels>,
 8794        target_display_point: DisplayPoint,
 8795        editor_width: Pixels,
 8796        window: &mut Window,
 8797        cx: &mut App,
 8798    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8799        if target_display_point.row().as_f32() < scroll_top {
 8800            let mut element = self
 8801                .render_edit_prediction_line_popover(
 8802                    "Jump to Edit",
 8803                    Some(IconName::ArrowUp),
 8804                    window,
 8805                    cx,
 8806                )?
 8807                .into_any();
 8808
 8809            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8810            let offset = point(
 8811                (text_bounds.size.width - size.width) / 2.,
 8812                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8813            );
 8814
 8815            let origin = text_bounds.origin + offset;
 8816            element.prepaint_at(origin, window, cx);
 8817            Some((element, origin))
 8818        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8819            let mut element = self
 8820                .render_edit_prediction_line_popover(
 8821                    "Jump to Edit",
 8822                    Some(IconName::ArrowDown),
 8823                    window,
 8824                    cx,
 8825                )?
 8826                .into_any();
 8827
 8828            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8829            let offset = point(
 8830                (text_bounds.size.width - size.width) / 2.,
 8831                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8832            );
 8833
 8834            let origin = text_bounds.origin + offset;
 8835            element.prepaint_at(origin, window, cx);
 8836            Some((element, origin))
 8837        } else {
 8838            self.render_edit_prediction_end_of_line_popover(
 8839                "Jump to Edit",
 8840                editor_snapshot,
 8841                visible_row_range,
 8842                target_display_point,
 8843                line_height,
 8844                scroll_pixel_position,
 8845                content_origin,
 8846                editor_width,
 8847                window,
 8848                cx,
 8849            )
 8850        }
 8851    }
 8852
 8853    fn render_edit_prediction_end_of_line_popover(
 8854        self: &mut Editor,
 8855        label: &'static str,
 8856        editor_snapshot: &EditorSnapshot,
 8857        visible_row_range: Range<DisplayRow>,
 8858        target_display_point: DisplayPoint,
 8859        line_height: Pixels,
 8860        scroll_pixel_position: gpui::Point<Pixels>,
 8861        content_origin: gpui::Point<Pixels>,
 8862        editor_width: Pixels,
 8863        window: &mut Window,
 8864        cx: &mut App,
 8865    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8866        let target_line_end = DisplayPoint::new(
 8867            target_display_point.row(),
 8868            editor_snapshot.line_len(target_display_point.row()),
 8869        );
 8870
 8871        let mut element = self
 8872            .render_edit_prediction_line_popover(label, None, window, cx)?
 8873            .into_any();
 8874
 8875        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8876
 8877        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8878
 8879        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8880        let mut origin = start_point
 8881            + line_origin
 8882            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8883        origin.x = origin.x.max(content_origin.x);
 8884
 8885        let max_x = content_origin.x + editor_width - size.width;
 8886
 8887        if origin.x > max_x {
 8888            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8889
 8890            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8891                origin.y += offset;
 8892                IconName::ArrowUp
 8893            } else {
 8894                origin.y -= offset;
 8895                IconName::ArrowDown
 8896            };
 8897
 8898            element = self
 8899                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8900                .into_any();
 8901
 8902            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8903
 8904            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8905        }
 8906
 8907        element.prepaint_at(origin, window, cx);
 8908        Some((element, origin))
 8909    }
 8910
 8911    fn render_edit_prediction_diff_popover(
 8912        self: &Editor,
 8913        text_bounds: &Bounds<Pixels>,
 8914        content_origin: gpui::Point<Pixels>,
 8915        right_margin: Pixels,
 8916        editor_snapshot: &EditorSnapshot,
 8917        visible_row_range: Range<DisplayRow>,
 8918        line_layouts: &[LineWithInvisibles],
 8919        line_height: Pixels,
 8920        scroll_pixel_position: gpui::Point<Pixels>,
 8921        newest_selection_head: Option<DisplayPoint>,
 8922        editor_width: Pixels,
 8923        style: &EditorStyle,
 8924        edits: &Vec<(Range<Anchor>, String)>,
 8925        edit_preview: &Option<language::EditPreview>,
 8926        snapshot: &language::BufferSnapshot,
 8927        window: &mut Window,
 8928        cx: &mut App,
 8929    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8930        let edit_start = edits
 8931            .first()
 8932            .unwrap()
 8933            .0
 8934            .start
 8935            .to_display_point(editor_snapshot);
 8936        let edit_end = edits
 8937            .last()
 8938            .unwrap()
 8939            .0
 8940            .end
 8941            .to_display_point(editor_snapshot);
 8942
 8943        let is_visible = visible_row_range.contains(&edit_start.row())
 8944            || visible_row_range.contains(&edit_end.row());
 8945        if !is_visible {
 8946            return None;
 8947        }
 8948
 8949        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8950            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8951        } else {
 8952            // Fallback for providers without edit_preview
 8953            crate::edit_prediction_fallback_text(edits, cx)
 8954        };
 8955
 8956        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8957        let line_count = highlighted_edits.text.lines().count();
 8958
 8959        const BORDER_WIDTH: Pixels = px(1.);
 8960
 8961        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8962        let has_keybind = keybind.is_some();
 8963
 8964        let mut element = h_flex()
 8965            .items_start()
 8966            .child(
 8967                h_flex()
 8968                    .bg(cx.theme().colors().editor_background)
 8969                    .border(BORDER_WIDTH)
 8970                    .shadow_xs()
 8971                    .border_color(cx.theme().colors().border)
 8972                    .rounded_l_lg()
 8973                    .when(line_count > 1, |el| el.rounded_br_lg())
 8974                    .pr_1()
 8975                    .child(styled_text),
 8976            )
 8977            .child(
 8978                h_flex()
 8979                    .h(line_height + BORDER_WIDTH * 2.)
 8980                    .px_1p5()
 8981                    .gap_1()
 8982                    // Workaround: For some reason, there's a gap if we don't do this
 8983                    .ml(-BORDER_WIDTH)
 8984                    .shadow(vec![gpui::BoxShadow {
 8985                        color: gpui::black().opacity(0.05),
 8986                        offset: point(px(1.), px(1.)),
 8987                        blur_radius: px(2.),
 8988                        spread_radius: px(0.),
 8989                    }])
 8990                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8991                    .border(BORDER_WIDTH)
 8992                    .border_color(cx.theme().colors().border)
 8993                    .rounded_r_lg()
 8994                    .id("edit_prediction_diff_popover_keybind")
 8995                    .when(!has_keybind, |el| {
 8996                        let status_colors = cx.theme().status();
 8997
 8998                        el.bg(status_colors.error_background)
 8999                            .border_color(status_colors.error.opacity(0.6))
 9000                            .child(Icon::new(IconName::Info).color(Color::Error))
 9001                            .cursor_default()
 9002                            .hoverable_tooltip(move |_window, cx| {
 9003                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9004                            })
 9005                    })
 9006                    .children(keybind),
 9007            )
 9008            .into_any();
 9009
 9010        let longest_row =
 9011            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9012        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9013            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9014        } else {
 9015            layout_line(
 9016                longest_row,
 9017                editor_snapshot,
 9018                style,
 9019                editor_width,
 9020                |_| false,
 9021                window,
 9022                cx,
 9023            )
 9024            .width
 9025        };
 9026
 9027        let viewport_bounds =
 9028            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9029                right: -right_margin,
 9030                ..Default::default()
 9031            });
 9032
 9033        let x_after_longest =
 9034            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9035                - scroll_pixel_position.x;
 9036
 9037        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9038
 9039        // Fully visible if it can be displayed within the window (allow overlapping other
 9040        // panes). However, this is only allowed if the popover starts within text_bounds.
 9041        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9042            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9043
 9044        let mut origin = if can_position_to_the_right {
 9045            point(
 9046                x_after_longest,
 9047                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9048                    - scroll_pixel_position.y,
 9049            )
 9050        } else {
 9051            let cursor_row = newest_selection_head.map(|head| head.row());
 9052            let above_edit = edit_start
 9053                .row()
 9054                .0
 9055                .checked_sub(line_count as u32)
 9056                .map(DisplayRow);
 9057            let below_edit = Some(edit_end.row() + 1);
 9058            let above_cursor =
 9059                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9060            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9061
 9062            // Place the edit popover adjacent to the edit if there is a location
 9063            // available that is onscreen and does not obscure the cursor. Otherwise,
 9064            // place it adjacent to the cursor.
 9065            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9066                .into_iter()
 9067                .flatten()
 9068                .find(|&start_row| {
 9069                    let end_row = start_row + line_count as u32;
 9070                    visible_row_range.contains(&start_row)
 9071                        && visible_row_range.contains(&end_row)
 9072                        && cursor_row
 9073                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9074                })?;
 9075
 9076            content_origin
 9077                + point(
 9078                    -scroll_pixel_position.x,
 9079                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9080                )
 9081        };
 9082
 9083        origin.x -= BORDER_WIDTH;
 9084
 9085        window.defer_draw(element, origin, 1);
 9086
 9087        // Do not return an element, since it will already be drawn due to defer_draw.
 9088        None
 9089    }
 9090
 9091    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9092        px(30.)
 9093    }
 9094
 9095    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9096        if self.read_only(cx) {
 9097            cx.theme().players().read_only()
 9098        } else {
 9099            self.style.as_ref().unwrap().local_player
 9100        }
 9101    }
 9102
 9103    fn render_edit_prediction_accept_keybind(
 9104        &self,
 9105        window: &mut Window,
 9106        cx: &App,
 9107    ) -> Option<AnyElement> {
 9108        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9109        let accept_keystroke = accept_binding.keystroke()?;
 9110
 9111        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9112
 9113        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9114            Color::Accent
 9115        } else {
 9116            Color::Muted
 9117        };
 9118
 9119        h_flex()
 9120            .px_0p5()
 9121            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9122            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9123            .text_size(TextSize::XSmall.rems(cx))
 9124            .child(h_flex().children(ui::render_modifiers(
 9125                accept_keystroke.modifiers(),
 9126                PlatformStyle::platform(),
 9127                Some(modifiers_color),
 9128                Some(IconSize::XSmall.rems().into()),
 9129                true,
 9130            )))
 9131            .when(is_platform_style_mac, |parent| {
 9132                parent.child(accept_keystroke.key().to_string())
 9133            })
 9134            .when(!is_platform_style_mac, |parent| {
 9135                parent.child(
 9136                    Key::new(
 9137                        util::capitalize(accept_keystroke.key()),
 9138                        Some(Color::Default),
 9139                    )
 9140                    .size(Some(IconSize::XSmall.rems().into())),
 9141                )
 9142            })
 9143            .into_any()
 9144            .into()
 9145    }
 9146
 9147    fn render_edit_prediction_line_popover(
 9148        &self,
 9149        label: impl Into<SharedString>,
 9150        icon: Option<IconName>,
 9151        window: &mut Window,
 9152        cx: &App,
 9153    ) -> Option<Stateful<Div>> {
 9154        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9155
 9156        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9157        let has_keybind = keybind.is_some();
 9158
 9159        let result = h_flex()
 9160            .id("ep-line-popover")
 9161            .py_0p5()
 9162            .pl_1()
 9163            .pr(padding_right)
 9164            .gap_1()
 9165            .rounded_md()
 9166            .border_1()
 9167            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9168            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9169            .shadow_xs()
 9170            .when(!has_keybind, |el| {
 9171                let status_colors = cx.theme().status();
 9172
 9173                el.bg(status_colors.error_background)
 9174                    .border_color(status_colors.error.opacity(0.6))
 9175                    .pl_2()
 9176                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9177                    .cursor_default()
 9178                    .hoverable_tooltip(move |_window, cx| {
 9179                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9180                    })
 9181            })
 9182            .children(keybind)
 9183            .child(
 9184                Label::new(label)
 9185                    .size(LabelSize::Small)
 9186                    .when(!has_keybind, |el| {
 9187                        el.color(cx.theme().status().error.into()).strikethrough()
 9188                    }),
 9189            )
 9190            .when(!has_keybind, |el| {
 9191                el.child(
 9192                    h_flex().ml_1().child(
 9193                        Icon::new(IconName::Info)
 9194                            .size(IconSize::Small)
 9195                            .color(cx.theme().status().error.into()),
 9196                    ),
 9197                )
 9198            })
 9199            .when_some(icon, |element, icon| {
 9200                element.child(
 9201                    div()
 9202                        .mt(px(1.5))
 9203                        .child(Icon::new(icon).size(IconSize::Small)),
 9204                )
 9205            });
 9206
 9207        Some(result)
 9208    }
 9209
 9210    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9211        let accent_color = cx.theme().colors().text_accent;
 9212        let editor_bg_color = cx.theme().colors().editor_background;
 9213        editor_bg_color.blend(accent_color.opacity(0.1))
 9214    }
 9215
 9216    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9217        let accent_color = cx.theme().colors().text_accent;
 9218        let editor_bg_color = cx.theme().colors().editor_background;
 9219        editor_bg_color.blend(accent_color.opacity(0.6))
 9220    }
 9221    fn get_prediction_provider_icon_name(
 9222        provider: &Option<RegisteredEditPredictionProvider>,
 9223    ) -> IconName {
 9224        match provider {
 9225            Some(provider) => match provider.provider.name() {
 9226                "copilot" => IconName::Copilot,
 9227                "supermaven" => IconName::Supermaven,
 9228                _ => IconName::ZedPredict,
 9229            },
 9230            None => IconName::ZedPredict,
 9231        }
 9232    }
 9233
 9234    fn render_edit_prediction_cursor_popover(
 9235        &self,
 9236        min_width: Pixels,
 9237        max_width: Pixels,
 9238        cursor_point: Point,
 9239        style: &EditorStyle,
 9240        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9241        _window: &Window,
 9242        cx: &mut Context<Editor>,
 9243    ) -> Option<AnyElement> {
 9244        let provider = self.edit_prediction_provider.as_ref()?;
 9245        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9246
 9247        let is_refreshing = provider.provider.is_refreshing(cx);
 9248
 9249        fn pending_completion_container(icon: IconName) -> Div {
 9250            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9251        }
 9252
 9253        let completion = match &self.active_edit_prediction {
 9254            Some(prediction) => {
 9255                if !self.has_visible_completions_menu() {
 9256                    const RADIUS: Pixels = px(6.);
 9257                    const BORDER_WIDTH: Pixels = px(1.);
 9258
 9259                    return Some(
 9260                        h_flex()
 9261                            .elevation_2(cx)
 9262                            .border(BORDER_WIDTH)
 9263                            .border_color(cx.theme().colors().border)
 9264                            .when(accept_keystroke.is_none(), |el| {
 9265                                el.border_color(cx.theme().status().error)
 9266                            })
 9267                            .rounded(RADIUS)
 9268                            .rounded_tl(px(0.))
 9269                            .overflow_hidden()
 9270                            .child(div().px_1p5().child(match &prediction.completion {
 9271                                EditPrediction::Move { target, snapshot } => {
 9272                                    use text::ToPoint as _;
 9273                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9274                                    {
 9275                                        Icon::new(IconName::ZedPredictDown)
 9276                                    } else {
 9277                                        Icon::new(IconName::ZedPredictUp)
 9278                                    }
 9279                                }
 9280                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9281                            }))
 9282                            .child(
 9283                                h_flex()
 9284                                    .gap_1()
 9285                                    .py_1()
 9286                                    .px_2()
 9287                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9288                                    .border_l_1()
 9289                                    .border_color(cx.theme().colors().border)
 9290                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9291                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9292                                        el.child(
 9293                                            Label::new("Hold")
 9294                                                .size(LabelSize::Small)
 9295                                                .when(accept_keystroke.is_none(), |el| {
 9296                                                    el.strikethrough()
 9297                                                })
 9298                                                .line_height_style(LineHeightStyle::UiLabel),
 9299                                        )
 9300                                    })
 9301                                    .id("edit_prediction_cursor_popover_keybind")
 9302                                    .when(accept_keystroke.is_none(), |el| {
 9303                                        let status_colors = cx.theme().status();
 9304
 9305                                        el.bg(status_colors.error_background)
 9306                                            .border_color(status_colors.error.opacity(0.6))
 9307                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9308                                            .cursor_default()
 9309                                            .hoverable_tooltip(move |_window, cx| {
 9310                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9311                                                    .into()
 9312                                            })
 9313                                    })
 9314                                    .when_some(
 9315                                        accept_keystroke.as_ref(),
 9316                                        |el, accept_keystroke| {
 9317                                            el.child(h_flex().children(ui::render_modifiers(
 9318                                                accept_keystroke.modifiers(),
 9319                                                PlatformStyle::platform(),
 9320                                                Some(Color::Default),
 9321                                                Some(IconSize::XSmall.rems().into()),
 9322                                                false,
 9323                                            )))
 9324                                        },
 9325                                    ),
 9326                            )
 9327                            .into_any(),
 9328                    );
 9329                }
 9330
 9331                self.render_edit_prediction_cursor_popover_preview(
 9332                    prediction,
 9333                    cursor_point,
 9334                    style,
 9335                    cx,
 9336                )?
 9337            }
 9338
 9339            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9340                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9341                    stale_completion,
 9342                    cursor_point,
 9343                    style,
 9344                    cx,
 9345                )?,
 9346
 9347                None => pending_completion_container(provider_icon)
 9348                    .child(Label::new("...").size(LabelSize::Small)),
 9349            },
 9350
 9351            None => pending_completion_container(provider_icon)
 9352                .child(Label::new("...").size(LabelSize::Small)),
 9353        };
 9354
 9355        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9356            completion
 9357                .with_animation(
 9358                    "loading-completion",
 9359                    Animation::new(Duration::from_secs(2))
 9360                        .repeat()
 9361                        .with_easing(pulsating_between(0.4, 0.8)),
 9362                    |label, delta| label.opacity(delta),
 9363                )
 9364                .into_any_element()
 9365        } else {
 9366            completion.into_any_element()
 9367        };
 9368
 9369        let has_completion = self.active_edit_prediction.is_some();
 9370
 9371        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9372        Some(
 9373            h_flex()
 9374                .min_w(min_width)
 9375                .max_w(max_width)
 9376                .flex_1()
 9377                .elevation_2(cx)
 9378                .border_color(cx.theme().colors().border)
 9379                .child(
 9380                    div()
 9381                        .flex_1()
 9382                        .py_1()
 9383                        .px_2()
 9384                        .overflow_hidden()
 9385                        .child(completion),
 9386                )
 9387                .when_some(accept_keystroke, |el, accept_keystroke| {
 9388                    if !accept_keystroke.modifiers().modified() {
 9389                        return el;
 9390                    }
 9391
 9392                    el.child(
 9393                        h_flex()
 9394                            .h_full()
 9395                            .border_l_1()
 9396                            .rounded_r_lg()
 9397                            .border_color(cx.theme().colors().border)
 9398                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9399                            .gap_1()
 9400                            .py_1()
 9401                            .px_2()
 9402                            .child(
 9403                                h_flex()
 9404                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9405                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9406                                    .child(h_flex().children(ui::render_modifiers(
 9407                                        accept_keystroke.modifiers(),
 9408                                        PlatformStyle::platform(),
 9409                                        Some(if !has_completion {
 9410                                            Color::Muted
 9411                                        } else {
 9412                                            Color::Default
 9413                                        }),
 9414                                        None,
 9415                                        false,
 9416                                    ))),
 9417                            )
 9418                            .child(Label::new("Preview").into_any_element())
 9419                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9420                    )
 9421                })
 9422                .into_any(),
 9423        )
 9424    }
 9425
 9426    fn render_edit_prediction_cursor_popover_preview(
 9427        &self,
 9428        completion: &EditPredictionState,
 9429        cursor_point: Point,
 9430        style: &EditorStyle,
 9431        cx: &mut Context<Editor>,
 9432    ) -> Option<Div> {
 9433        use text::ToPoint as _;
 9434
 9435        fn render_relative_row_jump(
 9436            prefix: impl Into<String>,
 9437            current_row: u32,
 9438            target_row: u32,
 9439        ) -> Div {
 9440            let (row_diff, arrow) = if target_row < current_row {
 9441                (current_row - target_row, IconName::ArrowUp)
 9442            } else {
 9443                (target_row - current_row, IconName::ArrowDown)
 9444            };
 9445
 9446            h_flex()
 9447                .child(
 9448                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9449                        .color(Color::Muted)
 9450                        .size(LabelSize::Small),
 9451                )
 9452                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9453        }
 9454
 9455        let supports_jump = self
 9456            .edit_prediction_provider
 9457            .as_ref()
 9458            .map(|provider| provider.provider.supports_jump_to_edit())
 9459            .unwrap_or(true);
 9460
 9461        match &completion.completion {
 9462            EditPrediction::Move {
 9463                target, snapshot, ..
 9464            } => {
 9465                if !supports_jump {
 9466                    return None;
 9467                }
 9468
 9469                Some(
 9470                    h_flex()
 9471                        .px_2()
 9472                        .gap_2()
 9473                        .flex_1()
 9474                        .child(
 9475                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9476                                Icon::new(IconName::ZedPredictDown)
 9477                            } else {
 9478                                Icon::new(IconName::ZedPredictUp)
 9479                            },
 9480                        )
 9481                        .child(Label::new("Jump to Edit")),
 9482                )
 9483            }
 9484
 9485            EditPrediction::Edit {
 9486                edits,
 9487                edit_preview,
 9488                snapshot,
 9489                display_mode: _,
 9490            } => {
 9491                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9492
 9493                let (highlighted_edits, has_more_lines) =
 9494                    if let Some(edit_preview) = edit_preview.as_ref() {
 9495                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9496                            .first_line_preview()
 9497                    } else {
 9498                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9499                    };
 9500
 9501                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9502                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9503
 9504                let preview = h_flex()
 9505                    .gap_1()
 9506                    .min_w_16()
 9507                    .child(styled_text)
 9508                    .when(has_more_lines, |parent| parent.child(""));
 9509
 9510                let left = if supports_jump && first_edit_row != cursor_point.row {
 9511                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9512                        .into_any_element()
 9513                } else {
 9514                    let icon_name =
 9515                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9516                    Icon::new(icon_name).into_any_element()
 9517                };
 9518
 9519                Some(
 9520                    h_flex()
 9521                        .h_full()
 9522                        .flex_1()
 9523                        .gap_2()
 9524                        .pr_1()
 9525                        .overflow_x_hidden()
 9526                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9527                        .child(left)
 9528                        .child(preview),
 9529                )
 9530            }
 9531        }
 9532    }
 9533
 9534    pub fn render_context_menu(
 9535        &self,
 9536        style: &EditorStyle,
 9537        max_height_in_lines: u32,
 9538        window: &mut Window,
 9539        cx: &mut Context<Editor>,
 9540    ) -> Option<AnyElement> {
 9541        let menu = self.context_menu.borrow();
 9542        let menu = menu.as_ref()?;
 9543        if !menu.visible() {
 9544            return None;
 9545        };
 9546        Some(menu.render(style, max_height_in_lines, window, cx))
 9547    }
 9548
 9549    fn render_context_menu_aside(
 9550        &mut self,
 9551        max_size: Size<Pixels>,
 9552        window: &mut Window,
 9553        cx: &mut Context<Editor>,
 9554    ) -> Option<AnyElement> {
 9555        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9556            if menu.visible() {
 9557                menu.render_aside(max_size, window, cx)
 9558            } else {
 9559                None
 9560            }
 9561        })
 9562    }
 9563
 9564    fn hide_context_menu(
 9565        &mut self,
 9566        window: &mut Window,
 9567        cx: &mut Context<Self>,
 9568    ) -> Option<CodeContextMenu> {
 9569        cx.notify();
 9570        self.completion_tasks.clear();
 9571        let context_menu = self.context_menu.borrow_mut().take();
 9572        self.stale_edit_prediction_in_menu.take();
 9573        self.update_visible_edit_prediction(window, cx);
 9574        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9575            && let Some(completion_provider) = &self.completion_provider
 9576        {
 9577            completion_provider.selection_changed(None, window, cx);
 9578        }
 9579        context_menu
 9580    }
 9581
 9582    fn show_snippet_choices(
 9583        &mut self,
 9584        choices: &Vec<String>,
 9585        selection: Range<Anchor>,
 9586        cx: &mut Context<Self>,
 9587    ) {
 9588        let Some((_, buffer, _)) = self
 9589            .buffer()
 9590            .read(cx)
 9591            .excerpt_containing(selection.start, cx)
 9592        else {
 9593            return;
 9594        };
 9595        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9596        else {
 9597            return;
 9598        };
 9599        if buffer != end_buffer {
 9600            log::error!("expected anchor range to have matching buffer IDs");
 9601            return;
 9602        }
 9603
 9604        let id = post_inc(&mut self.next_completion_id);
 9605        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9606        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9607            CompletionsMenu::new_snippet_choices(
 9608                id,
 9609                true,
 9610                choices,
 9611                selection,
 9612                buffer,
 9613                snippet_sort_order,
 9614            ),
 9615        ));
 9616    }
 9617
 9618    pub fn insert_snippet(
 9619        &mut self,
 9620        insertion_ranges: &[Range<usize>],
 9621        snippet: Snippet,
 9622        window: &mut Window,
 9623        cx: &mut Context<Self>,
 9624    ) -> Result<()> {
 9625        struct Tabstop<T> {
 9626            is_end_tabstop: bool,
 9627            ranges: Vec<Range<T>>,
 9628            choices: Option<Vec<String>>,
 9629        }
 9630
 9631        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9632            let snippet_text: Arc<str> = snippet.text.clone().into();
 9633            let edits = insertion_ranges
 9634                .iter()
 9635                .cloned()
 9636                .map(|range| (range, snippet_text.clone()));
 9637            let autoindent_mode = AutoindentMode::Block {
 9638                original_indent_columns: Vec::new(),
 9639            };
 9640            buffer.edit(edits, Some(autoindent_mode), cx);
 9641
 9642            let snapshot = &*buffer.read(cx);
 9643            let snippet = &snippet;
 9644            snippet
 9645                .tabstops
 9646                .iter()
 9647                .map(|tabstop| {
 9648                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9649                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9650                    });
 9651                    let mut tabstop_ranges = tabstop
 9652                        .ranges
 9653                        .iter()
 9654                        .flat_map(|tabstop_range| {
 9655                            let mut delta = 0_isize;
 9656                            insertion_ranges.iter().map(move |insertion_range| {
 9657                                let insertion_start = insertion_range.start as isize + delta;
 9658                                delta +=
 9659                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9660
 9661                                let start = ((insertion_start + tabstop_range.start) as usize)
 9662                                    .min(snapshot.len());
 9663                                let end = ((insertion_start + tabstop_range.end) as usize)
 9664                                    .min(snapshot.len());
 9665                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9666                            })
 9667                        })
 9668                        .collect::<Vec<_>>();
 9669                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9670
 9671                    Tabstop {
 9672                        is_end_tabstop,
 9673                        ranges: tabstop_ranges,
 9674                        choices: tabstop.choices.clone(),
 9675                    }
 9676                })
 9677                .collect::<Vec<_>>()
 9678        });
 9679        if let Some(tabstop) = tabstops.first() {
 9680            self.change_selections(Default::default(), window, cx, |s| {
 9681                // Reverse order so that the first range is the newest created selection.
 9682                // Completions will use it and autoscroll will prioritize it.
 9683                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9684            });
 9685
 9686            if let Some(choices) = &tabstop.choices
 9687                && let Some(selection) = tabstop.ranges.first()
 9688            {
 9689                self.show_snippet_choices(choices, selection.clone(), cx)
 9690            }
 9691
 9692            // If we're already at the last tabstop and it's at the end of the snippet,
 9693            // we're done, we don't need to keep the state around.
 9694            if !tabstop.is_end_tabstop {
 9695                let choices = tabstops
 9696                    .iter()
 9697                    .map(|tabstop| tabstop.choices.clone())
 9698                    .collect();
 9699
 9700                let ranges = tabstops
 9701                    .into_iter()
 9702                    .map(|tabstop| tabstop.ranges)
 9703                    .collect::<Vec<_>>();
 9704
 9705                self.snippet_stack.push(SnippetState {
 9706                    active_index: 0,
 9707                    ranges,
 9708                    choices,
 9709                });
 9710            }
 9711
 9712            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9713            if self.autoclose_regions.is_empty() {
 9714                let snapshot = self.buffer.read(cx).snapshot(cx);
 9715                let mut all_selections = self.selections.all::<Point>(cx);
 9716                for selection in &mut all_selections {
 9717                    let selection_head = selection.head();
 9718                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9719                        continue;
 9720                    };
 9721
 9722                    let mut bracket_pair = None;
 9723                    let max_lookup_length = scope
 9724                        .brackets()
 9725                        .map(|(pair, _)| {
 9726                            pair.start
 9727                                .as_str()
 9728                                .chars()
 9729                                .count()
 9730                                .max(pair.end.as_str().chars().count())
 9731                        })
 9732                        .max();
 9733                    if let Some(max_lookup_length) = max_lookup_length {
 9734                        let next_text = snapshot
 9735                            .chars_at(selection_head)
 9736                            .take(max_lookup_length)
 9737                            .collect::<String>();
 9738                        let prev_text = snapshot
 9739                            .reversed_chars_at(selection_head)
 9740                            .take(max_lookup_length)
 9741                            .collect::<String>();
 9742
 9743                        for (pair, enabled) in scope.brackets() {
 9744                            if enabled
 9745                                && pair.close
 9746                                && prev_text.starts_with(pair.start.as_str())
 9747                                && next_text.starts_with(pair.end.as_str())
 9748                            {
 9749                                bracket_pair = Some(pair.clone());
 9750                                break;
 9751                            }
 9752                        }
 9753                    }
 9754
 9755                    if let Some(pair) = bracket_pair {
 9756                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9757                        let autoclose_enabled =
 9758                            self.use_autoclose && snapshot_settings.use_autoclose;
 9759                        if autoclose_enabled {
 9760                            let start = snapshot.anchor_after(selection_head);
 9761                            let end = snapshot.anchor_after(selection_head);
 9762                            self.autoclose_regions.push(AutocloseRegion {
 9763                                selection_id: selection.id,
 9764                                range: start..end,
 9765                                pair,
 9766                            });
 9767                        }
 9768                    }
 9769                }
 9770            }
 9771        }
 9772        Ok(())
 9773    }
 9774
 9775    pub fn move_to_next_snippet_tabstop(
 9776        &mut self,
 9777        window: &mut Window,
 9778        cx: &mut Context<Self>,
 9779    ) -> bool {
 9780        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9781    }
 9782
 9783    pub fn move_to_prev_snippet_tabstop(
 9784        &mut self,
 9785        window: &mut Window,
 9786        cx: &mut Context<Self>,
 9787    ) -> bool {
 9788        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9789    }
 9790
 9791    pub fn move_to_snippet_tabstop(
 9792        &mut self,
 9793        bias: Bias,
 9794        window: &mut Window,
 9795        cx: &mut Context<Self>,
 9796    ) -> bool {
 9797        if let Some(mut snippet) = self.snippet_stack.pop() {
 9798            match bias {
 9799                Bias::Left => {
 9800                    if snippet.active_index > 0 {
 9801                        snippet.active_index -= 1;
 9802                    } else {
 9803                        self.snippet_stack.push(snippet);
 9804                        return false;
 9805                    }
 9806                }
 9807                Bias::Right => {
 9808                    if snippet.active_index + 1 < snippet.ranges.len() {
 9809                        snippet.active_index += 1;
 9810                    } else {
 9811                        self.snippet_stack.push(snippet);
 9812                        return false;
 9813                    }
 9814                }
 9815            }
 9816            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9817                self.change_selections(Default::default(), window, cx, |s| {
 9818                    // Reverse order so that the first range is the newest created selection.
 9819                    // Completions will use it and autoscroll will prioritize it.
 9820                    s.select_ranges(current_ranges.iter().rev().cloned())
 9821                });
 9822
 9823                if let Some(choices) = &snippet.choices[snippet.active_index]
 9824                    && let Some(selection) = current_ranges.first()
 9825                {
 9826                    self.show_snippet_choices(choices, selection.clone(), cx);
 9827                }
 9828
 9829                // If snippet state is not at the last tabstop, push it back on the stack
 9830                if snippet.active_index + 1 < snippet.ranges.len() {
 9831                    self.snippet_stack.push(snippet);
 9832                }
 9833                return true;
 9834            }
 9835        }
 9836
 9837        false
 9838    }
 9839
 9840    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9841        self.transact(window, cx, |this, window, cx| {
 9842            this.select_all(&SelectAll, window, cx);
 9843            this.insert("", window, cx);
 9844        });
 9845    }
 9846
 9847    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9848        if self.read_only(cx) {
 9849            return;
 9850        }
 9851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9852        self.transact(window, cx, |this, window, cx| {
 9853            this.select_autoclose_pair(window, cx);
 9854            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9855            if !this.linked_edit_ranges.is_empty() {
 9856                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9857                let snapshot = this.buffer.read(cx).snapshot(cx);
 9858
 9859                for selection in selections.iter() {
 9860                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9861                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9862                    if selection_start.buffer_id != selection_end.buffer_id {
 9863                        continue;
 9864                    }
 9865                    if let Some(ranges) =
 9866                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9867                    {
 9868                        for (buffer, entries) in ranges {
 9869                            linked_ranges.entry(buffer).or_default().extend(entries);
 9870                        }
 9871                    }
 9872                }
 9873            }
 9874
 9875            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9876            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9877            for selection in &mut selections {
 9878                if selection.is_empty() {
 9879                    let old_head = selection.head();
 9880                    let mut new_head =
 9881                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9882                            .to_point(&display_map);
 9883                    if let Some((buffer, line_buffer_range)) = display_map
 9884                        .buffer_snapshot
 9885                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9886                    {
 9887                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9888                        let indent_len = match indent_size.kind {
 9889                            IndentKind::Space => {
 9890                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9891                            }
 9892                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9893                        };
 9894                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9895                            let indent_len = indent_len.get();
 9896                            new_head = cmp::min(
 9897                                new_head,
 9898                                MultiBufferPoint::new(
 9899                                    old_head.row,
 9900                                    ((old_head.column - 1) / indent_len) * indent_len,
 9901                                ),
 9902                            );
 9903                        }
 9904                    }
 9905
 9906                    selection.set_head(new_head, SelectionGoal::None);
 9907                }
 9908            }
 9909
 9910            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9911            this.insert("", window, cx);
 9912            let empty_str: Arc<str> = Arc::from("");
 9913            for (buffer, edits) in linked_ranges {
 9914                let snapshot = buffer.read(cx).snapshot();
 9915                use text::ToPoint as TP;
 9916
 9917                let edits = edits
 9918                    .into_iter()
 9919                    .map(|range| {
 9920                        let end_point = TP::to_point(&range.end, &snapshot);
 9921                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9922
 9923                        if end_point == start_point {
 9924                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9925                                .saturating_sub(1);
 9926                            start_point =
 9927                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9928                        };
 9929
 9930                        (start_point..end_point, empty_str.clone())
 9931                    })
 9932                    .sorted_by_key(|(range, _)| range.start)
 9933                    .collect::<Vec<_>>();
 9934                buffer.update(cx, |this, cx| {
 9935                    this.edit(edits, None, cx);
 9936                })
 9937            }
 9938            this.refresh_edit_prediction(true, false, window, cx);
 9939            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9940        });
 9941    }
 9942
 9943    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9944        if self.read_only(cx) {
 9945            return;
 9946        }
 9947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9948        self.transact(window, cx, |this, window, cx| {
 9949            this.change_selections(Default::default(), window, cx, |s| {
 9950                s.move_with(|map, selection| {
 9951                    if selection.is_empty() {
 9952                        let cursor = movement::right(map, selection.head());
 9953                        selection.end = cursor;
 9954                        selection.reversed = true;
 9955                        selection.goal = SelectionGoal::None;
 9956                    }
 9957                })
 9958            });
 9959            this.insert("", window, cx);
 9960            this.refresh_edit_prediction(true, false, window, cx);
 9961        });
 9962    }
 9963
 9964    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9965        if self.mode.is_single_line() {
 9966            cx.propagate();
 9967            return;
 9968        }
 9969
 9970        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9971        if self.move_to_prev_snippet_tabstop(window, cx) {
 9972            return;
 9973        }
 9974        self.outdent(&Outdent, window, cx);
 9975    }
 9976
 9977    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9978        if self.mode.is_single_line() {
 9979            cx.propagate();
 9980            return;
 9981        }
 9982
 9983        if self.move_to_next_snippet_tabstop(window, cx) {
 9984            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9985            return;
 9986        }
 9987        if self.read_only(cx) {
 9988            return;
 9989        }
 9990        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9991        let mut selections = self.selections.all_adjusted(cx);
 9992        let buffer = self.buffer.read(cx);
 9993        let snapshot = buffer.snapshot(cx);
 9994        let rows_iter = selections.iter().map(|s| s.head().row);
 9995        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9996
 9997        let has_some_cursor_in_whitespace = selections
 9998            .iter()
 9999            .filter(|selection| selection.is_empty())
10000            .any(|selection| {
10001                let cursor = selection.head();
10002                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10003                cursor.column < current_indent.len
10004            });
10005
10006        let mut edits = Vec::new();
10007        let mut prev_edited_row = 0;
10008        let mut row_delta = 0;
10009        for selection in &mut selections {
10010            if selection.start.row != prev_edited_row {
10011                row_delta = 0;
10012            }
10013            prev_edited_row = selection.end.row;
10014
10015            // If the selection is non-empty, then increase the indentation of the selected lines.
10016            if !selection.is_empty() {
10017                row_delta =
10018                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10019                continue;
10020            }
10021
10022            let cursor = selection.head();
10023            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10024            if let Some(suggested_indent) =
10025                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10026            {
10027                // Don't do anything if already at suggested indent
10028                // and there is any other cursor which is not
10029                if has_some_cursor_in_whitespace
10030                    && cursor.column == current_indent.len
10031                    && current_indent.len == suggested_indent.len
10032                {
10033                    continue;
10034                }
10035
10036                // Adjust line and move cursor to suggested indent
10037                // if cursor is not at suggested indent
10038                if cursor.column < suggested_indent.len
10039                    && cursor.column <= current_indent.len
10040                    && current_indent.len <= suggested_indent.len
10041                {
10042                    selection.start = Point::new(cursor.row, suggested_indent.len);
10043                    selection.end = selection.start;
10044                    if row_delta == 0 {
10045                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10046                            cursor.row,
10047                            current_indent,
10048                            suggested_indent,
10049                        ));
10050                        row_delta = suggested_indent.len - current_indent.len;
10051                    }
10052                    continue;
10053                }
10054
10055                // If current indent is more than suggested indent
10056                // only move cursor to current indent and skip indent
10057                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10058                    selection.start = Point::new(cursor.row, current_indent.len);
10059                    selection.end = selection.start;
10060                    continue;
10061                }
10062            }
10063
10064            // Otherwise, insert a hard or soft tab.
10065            let settings = buffer.language_settings_at(cursor, cx);
10066            let tab_size = if settings.hard_tabs {
10067                IndentSize::tab()
10068            } else {
10069                let tab_size = settings.tab_size.get();
10070                let indent_remainder = snapshot
10071                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10072                    .flat_map(str::chars)
10073                    .fold(row_delta % tab_size, |counter: u32, c| {
10074                        if c == '\t' {
10075                            0
10076                        } else {
10077                            (counter + 1) % tab_size
10078                        }
10079                    });
10080
10081                let chars_to_next_tab_stop = tab_size - indent_remainder;
10082                IndentSize::spaces(chars_to_next_tab_stop)
10083            };
10084            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10085            selection.end = selection.start;
10086            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10087            row_delta += tab_size.len;
10088        }
10089
10090        self.transact(window, cx, |this, window, cx| {
10091            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10092            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10093            this.refresh_edit_prediction(true, false, window, cx);
10094        });
10095    }
10096
10097    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10098        if self.read_only(cx) {
10099            return;
10100        }
10101        if self.mode.is_single_line() {
10102            cx.propagate();
10103            return;
10104        }
10105
10106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10107        let mut selections = self.selections.all::<Point>(cx);
10108        let mut prev_edited_row = 0;
10109        let mut row_delta = 0;
10110        let mut edits = Vec::new();
10111        let buffer = self.buffer.read(cx);
10112        let snapshot = buffer.snapshot(cx);
10113        for selection in &mut selections {
10114            if selection.start.row != prev_edited_row {
10115                row_delta = 0;
10116            }
10117            prev_edited_row = selection.end.row;
10118
10119            row_delta =
10120                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10121        }
10122
10123        self.transact(window, cx, |this, window, cx| {
10124            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10125            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10126        });
10127    }
10128
10129    fn indent_selection(
10130        buffer: &MultiBuffer,
10131        snapshot: &MultiBufferSnapshot,
10132        selection: &mut Selection<Point>,
10133        edits: &mut Vec<(Range<Point>, String)>,
10134        delta_for_start_row: u32,
10135        cx: &App,
10136    ) -> u32 {
10137        let settings = buffer.language_settings_at(selection.start, cx);
10138        let tab_size = settings.tab_size.get();
10139        let indent_kind = if settings.hard_tabs {
10140            IndentKind::Tab
10141        } else {
10142            IndentKind::Space
10143        };
10144        let mut start_row = selection.start.row;
10145        let mut end_row = selection.end.row + 1;
10146
10147        // If a selection ends at the beginning of a line, don't indent
10148        // that last line.
10149        if selection.end.column == 0 && selection.end.row > selection.start.row {
10150            end_row -= 1;
10151        }
10152
10153        // Avoid re-indenting a row that has already been indented by a
10154        // previous selection, but still update this selection's column
10155        // to reflect that indentation.
10156        if delta_for_start_row > 0 {
10157            start_row += 1;
10158            selection.start.column += delta_for_start_row;
10159            if selection.end.row == selection.start.row {
10160                selection.end.column += delta_for_start_row;
10161            }
10162        }
10163
10164        let mut delta_for_end_row = 0;
10165        let has_multiple_rows = start_row + 1 != end_row;
10166        for row in start_row..end_row {
10167            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10168            let indent_delta = match (current_indent.kind, indent_kind) {
10169                (IndentKind::Space, IndentKind::Space) => {
10170                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10171                    IndentSize::spaces(columns_to_next_tab_stop)
10172                }
10173                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10174                (_, IndentKind::Tab) => IndentSize::tab(),
10175            };
10176
10177            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10178                0
10179            } else {
10180                selection.start.column
10181            };
10182            let row_start = Point::new(row, start);
10183            edits.push((
10184                row_start..row_start,
10185                indent_delta.chars().collect::<String>(),
10186            ));
10187
10188            // Update this selection's endpoints to reflect the indentation.
10189            if row == selection.start.row {
10190                selection.start.column += indent_delta.len;
10191            }
10192            if row == selection.end.row {
10193                selection.end.column += indent_delta.len;
10194                delta_for_end_row = indent_delta.len;
10195            }
10196        }
10197
10198        if selection.start.row == selection.end.row {
10199            delta_for_start_row + delta_for_end_row
10200        } else {
10201            delta_for_end_row
10202        }
10203    }
10204
10205    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10206        if self.read_only(cx) {
10207            return;
10208        }
10209        if self.mode.is_single_line() {
10210            cx.propagate();
10211            return;
10212        }
10213
10214        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10215        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10216        let selections = self.selections.all::<Point>(cx);
10217        let mut deletion_ranges = Vec::new();
10218        let mut last_outdent = None;
10219        {
10220            let buffer = self.buffer.read(cx);
10221            let snapshot = buffer.snapshot(cx);
10222            for selection in &selections {
10223                let settings = buffer.language_settings_at(selection.start, cx);
10224                let tab_size = settings.tab_size.get();
10225                let mut rows = selection.spanned_rows(false, &display_map);
10226
10227                // Avoid re-outdenting a row that has already been outdented by a
10228                // previous selection.
10229                if let Some(last_row) = last_outdent
10230                    && last_row == rows.start
10231                {
10232                    rows.start = rows.start.next_row();
10233                }
10234                let has_multiple_rows = rows.len() > 1;
10235                for row in rows.iter_rows() {
10236                    let indent_size = snapshot.indent_size_for_line(row);
10237                    if indent_size.len > 0 {
10238                        let deletion_len = match indent_size.kind {
10239                            IndentKind::Space => {
10240                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10241                                if columns_to_prev_tab_stop == 0 {
10242                                    tab_size
10243                                } else {
10244                                    columns_to_prev_tab_stop
10245                                }
10246                            }
10247                            IndentKind::Tab => 1,
10248                        };
10249                        let start = if has_multiple_rows
10250                            || deletion_len > selection.start.column
10251                            || indent_size.len < selection.start.column
10252                        {
10253                            0
10254                        } else {
10255                            selection.start.column - deletion_len
10256                        };
10257                        deletion_ranges.push(
10258                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10259                        );
10260                        last_outdent = Some(row);
10261                    }
10262                }
10263            }
10264        }
10265
10266        self.transact(window, cx, |this, window, cx| {
10267            this.buffer.update(cx, |buffer, cx| {
10268                let empty_str: Arc<str> = Arc::default();
10269                buffer.edit(
10270                    deletion_ranges
10271                        .into_iter()
10272                        .map(|range| (range, empty_str.clone())),
10273                    None,
10274                    cx,
10275                );
10276            });
10277            let selections = this.selections.all::<usize>(cx);
10278            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10279        });
10280    }
10281
10282    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10283        if self.read_only(cx) {
10284            return;
10285        }
10286        if self.mode.is_single_line() {
10287            cx.propagate();
10288            return;
10289        }
10290
10291        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10292        let selections = self
10293            .selections
10294            .all::<usize>(cx)
10295            .into_iter()
10296            .map(|s| s.range());
10297
10298        self.transact(window, cx, |this, window, cx| {
10299            this.buffer.update(cx, |buffer, cx| {
10300                buffer.autoindent_ranges(selections, cx);
10301            });
10302            let selections = this.selections.all::<usize>(cx);
10303            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10304        });
10305    }
10306
10307    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10310        let selections = self.selections.all::<Point>(cx);
10311
10312        let mut new_cursors = Vec::new();
10313        let mut edit_ranges = Vec::new();
10314        let mut selections = selections.iter().peekable();
10315        while let Some(selection) = selections.next() {
10316            let mut rows = selection.spanned_rows(false, &display_map);
10317            let goal_display_column = selection.head().to_display_point(&display_map).column();
10318
10319            // Accumulate contiguous regions of rows that we want to delete.
10320            while let Some(next_selection) = selections.peek() {
10321                let next_rows = next_selection.spanned_rows(false, &display_map);
10322                if next_rows.start <= rows.end {
10323                    rows.end = next_rows.end;
10324                    selections.next().unwrap();
10325                } else {
10326                    break;
10327                }
10328            }
10329
10330            let buffer = &display_map.buffer_snapshot;
10331            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10332            let edit_end;
10333            let cursor_buffer_row;
10334            if buffer.max_point().row >= rows.end.0 {
10335                // If there's a line after the range, delete the \n from the end of the row range
10336                // and position the cursor on the next line.
10337                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10338                cursor_buffer_row = rows.end;
10339            } else {
10340                // If there isn't a line after the range, delete the \n from the line before the
10341                // start of the row range and position the cursor there.
10342                edit_start = edit_start.saturating_sub(1);
10343                edit_end = buffer.len();
10344                cursor_buffer_row = rows.start.previous_row();
10345            }
10346
10347            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10348            *cursor.column_mut() =
10349                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10350
10351            new_cursors.push((
10352                selection.id,
10353                buffer.anchor_after(cursor.to_point(&display_map)),
10354            ));
10355            edit_ranges.push(edit_start..edit_end);
10356        }
10357
10358        self.transact(window, cx, |this, window, cx| {
10359            let buffer = this.buffer.update(cx, |buffer, cx| {
10360                let empty_str: Arc<str> = Arc::default();
10361                buffer.edit(
10362                    edit_ranges
10363                        .into_iter()
10364                        .map(|range| (range, empty_str.clone())),
10365                    None,
10366                    cx,
10367                );
10368                buffer.snapshot(cx)
10369            });
10370            let new_selections = new_cursors
10371                .into_iter()
10372                .map(|(id, cursor)| {
10373                    let cursor = cursor.to_point(&buffer);
10374                    Selection {
10375                        id,
10376                        start: cursor,
10377                        end: cursor,
10378                        reversed: false,
10379                        goal: SelectionGoal::None,
10380                    }
10381                })
10382                .collect();
10383
10384            this.change_selections(Default::default(), window, cx, |s| {
10385                s.select(new_selections);
10386            });
10387        });
10388    }
10389
10390    pub fn join_lines_impl(
10391        &mut self,
10392        insert_whitespace: bool,
10393        window: &mut Window,
10394        cx: &mut Context<Self>,
10395    ) {
10396        if self.read_only(cx) {
10397            return;
10398        }
10399        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10400        for selection in self.selections.all::<Point>(cx) {
10401            let start = MultiBufferRow(selection.start.row);
10402            // Treat single line selections as if they include the next line. Otherwise this action
10403            // would do nothing for single line selections individual cursors.
10404            let end = if selection.start.row == selection.end.row {
10405                MultiBufferRow(selection.start.row + 1)
10406            } else {
10407                MultiBufferRow(selection.end.row)
10408            };
10409
10410            if let Some(last_row_range) = row_ranges.last_mut()
10411                && start <= last_row_range.end
10412            {
10413                last_row_range.end = end;
10414                continue;
10415            }
10416            row_ranges.push(start..end);
10417        }
10418
10419        let snapshot = self.buffer.read(cx).snapshot(cx);
10420        let mut cursor_positions = Vec::new();
10421        for row_range in &row_ranges {
10422            let anchor = snapshot.anchor_before(Point::new(
10423                row_range.end.previous_row().0,
10424                snapshot.line_len(row_range.end.previous_row()),
10425            ));
10426            cursor_positions.push(anchor..anchor);
10427        }
10428
10429        self.transact(window, cx, |this, window, cx| {
10430            for row_range in row_ranges.into_iter().rev() {
10431                for row in row_range.iter_rows().rev() {
10432                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10433                    let next_line_row = row.next_row();
10434                    let indent = snapshot.indent_size_for_line(next_line_row);
10435                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10436
10437                    let replace =
10438                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10439                            " "
10440                        } else {
10441                            ""
10442                        };
10443
10444                    this.buffer.update(cx, |buffer, cx| {
10445                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10446                    });
10447                }
10448            }
10449
10450            this.change_selections(Default::default(), window, cx, |s| {
10451                s.select_anchor_ranges(cursor_positions)
10452            });
10453        });
10454    }
10455
10456    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10458        self.join_lines_impl(true, window, cx);
10459    }
10460
10461    pub fn sort_lines_case_sensitive(
10462        &mut self,
10463        _: &SortLinesCaseSensitive,
10464        window: &mut Window,
10465        cx: &mut Context<Self>,
10466    ) {
10467        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10468    }
10469
10470    pub fn sort_lines_by_length(
10471        &mut self,
10472        _: &SortLinesByLength,
10473        window: &mut Window,
10474        cx: &mut Context<Self>,
10475    ) {
10476        self.manipulate_immutable_lines(window, cx, |lines| {
10477            lines.sort_by_key(|&line| line.chars().count())
10478        })
10479    }
10480
10481    pub fn sort_lines_case_insensitive(
10482        &mut self,
10483        _: &SortLinesCaseInsensitive,
10484        window: &mut Window,
10485        cx: &mut Context<Self>,
10486    ) {
10487        self.manipulate_immutable_lines(window, cx, |lines| {
10488            lines.sort_by_key(|line| line.to_lowercase())
10489        })
10490    }
10491
10492    pub fn unique_lines_case_insensitive(
10493        &mut self,
10494        _: &UniqueLinesCaseInsensitive,
10495        window: &mut Window,
10496        cx: &mut Context<Self>,
10497    ) {
10498        self.manipulate_immutable_lines(window, cx, |lines| {
10499            let mut seen = HashSet::default();
10500            lines.retain(|line| seen.insert(line.to_lowercase()));
10501        })
10502    }
10503
10504    pub fn unique_lines_case_sensitive(
10505        &mut self,
10506        _: &UniqueLinesCaseSensitive,
10507        window: &mut Window,
10508        cx: &mut Context<Self>,
10509    ) {
10510        self.manipulate_immutable_lines(window, cx, |lines| {
10511            let mut seen = HashSet::default();
10512            lines.retain(|line| seen.insert(*line));
10513        })
10514    }
10515
10516    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10517        let snapshot = self.buffer.read(cx).snapshot(cx);
10518        for selection in self.selections.disjoint_anchors_arc().iter() {
10519            if snapshot
10520                .language_at(selection.start)
10521                .and_then(|lang| lang.config().wrap_characters.as_ref())
10522                .is_some()
10523            {
10524                return true;
10525            }
10526        }
10527        false
10528    }
10529
10530    fn wrap_selections_in_tag(
10531        &mut self,
10532        _: &WrapSelectionsInTag,
10533        window: &mut Window,
10534        cx: &mut Context<Self>,
10535    ) {
10536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10537
10538        let snapshot = self.buffer.read(cx).snapshot(cx);
10539
10540        let mut edits = Vec::new();
10541        let mut boundaries = Vec::new();
10542
10543        for selection in self.selections.all::<Point>(cx).iter() {
10544            let Some(wrap_config) = snapshot
10545                .language_at(selection.start)
10546                .and_then(|lang| lang.config().wrap_characters.clone())
10547            else {
10548                continue;
10549            };
10550
10551            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10552            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10553
10554            let start_before = snapshot.anchor_before(selection.start);
10555            let end_after = snapshot.anchor_after(selection.end);
10556
10557            edits.push((start_before..start_before, open_tag));
10558            edits.push((end_after..end_after, close_tag));
10559
10560            boundaries.push((
10561                start_before,
10562                end_after,
10563                wrap_config.start_prefix.len(),
10564                wrap_config.end_suffix.len(),
10565            ));
10566        }
10567
10568        if edits.is_empty() {
10569            return;
10570        }
10571
10572        self.transact(window, cx, |this, window, cx| {
10573            let buffer = this.buffer.update(cx, |buffer, cx| {
10574                buffer.edit(edits, None, cx);
10575                buffer.snapshot(cx)
10576            });
10577
10578            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10579            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10580                boundaries.into_iter()
10581            {
10582                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10583                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10584                new_selections.push(open_offset..open_offset);
10585                new_selections.push(close_offset..close_offset);
10586            }
10587
10588            this.change_selections(Default::default(), window, cx, |s| {
10589                s.select_ranges(new_selections);
10590            });
10591
10592            this.request_autoscroll(Autoscroll::fit(), cx);
10593        });
10594    }
10595
10596    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10597        let Some(project) = self.project.clone() else {
10598            return;
10599        };
10600        self.reload(project, window, cx)
10601            .detach_and_notify_err(window, cx);
10602    }
10603
10604    pub fn restore_file(
10605        &mut self,
10606        _: &::git::RestoreFile,
10607        window: &mut Window,
10608        cx: &mut Context<Self>,
10609    ) {
10610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10611        let mut buffer_ids = HashSet::default();
10612        let snapshot = self.buffer().read(cx).snapshot(cx);
10613        for selection in self.selections.all::<usize>(cx) {
10614            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10615        }
10616
10617        let buffer = self.buffer().read(cx);
10618        let ranges = buffer_ids
10619            .into_iter()
10620            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10621            .collect::<Vec<_>>();
10622
10623        self.restore_hunks_in_ranges(ranges, window, cx);
10624    }
10625
10626    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10628        let selections = self
10629            .selections
10630            .all(cx)
10631            .into_iter()
10632            .map(|s| s.range())
10633            .collect();
10634        self.restore_hunks_in_ranges(selections, window, cx);
10635    }
10636
10637    pub fn restore_hunks_in_ranges(
10638        &mut self,
10639        ranges: Vec<Range<Point>>,
10640        window: &mut Window,
10641        cx: &mut Context<Editor>,
10642    ) {
10643        let mut revert_changes = HashMap::default();
10644        let chunk_by = self
10645            .snapshot(window, cx)
10646            .hunks_for_ranges(ranges)
10647            .into_iter()
10648            .chunk_by(|hunk| hunk.buffer_id);
10649        for (buffer_id, hunks) in &chunk_by {
10650            let hunks = hunks.collect::<Vec<_>>();
10651            for hunk in &hunks {
10652                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10653            }
10654            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10655        }
10656        drop(chunk_by);
10657        if !revert_changes.is_empty() {
10658            self.transact(window, cx, |editor, window, cx| {
10659                editor.restore(revert_changes, window, cx);
10660            });
10661        }
10662    }
10663
10664    pub fn open_active_item_in_terminal(
10665        &mut self,
10666        _: &OpenInTerminal,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10671            let project_path = buffer.read(cx).project_path(cx)?;
10672            let project = self.project()?.read(cx);
10673            let entry = project.entry_for_path(&project_path, cx)?;
10674            let parent = match &entry.canonical_path {
10675                Some(canonical_path) => canonical_path.to_path_buf(),
10676                None => project.absolute_path(&project_path, cx)?,
10677            }
10678            .parent()?
10679            .to_path_buf();
10680            Some(parent)
10681        }) {
10682            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10683        }
10684    }
10685
10686    fn set_breakpoint_context_menu(
10687        &mut self,
10688        display_row: DisplayRow,
10689        position: Option<Anchor>,
10690        clicked_point: gpui::Point<Pixels>,
10691        window: &mut Window,
10692        cx: &mut Context<Self>,
10693    ) {
10694        let source = self
10695            .buffer
10696            .read(cx)
10697            .snapshot(cx)
10698            .anchor_before(Point::new(display_row.0, 0u32));
10699
10700        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10701
10702        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10703            self,
10704            source,
10705            clicked_point,
10706            context_menu,
10707            window,
10708            cx,
10709        );
10710    }
10711
10712    fn add_edit_breakpoint_block(
10713        &mut self,
10714        anchor: Anchor,
10715        breakpoint: &Breakpoint,
10716        edit_action: BreakpointPromptEditAction,
10717        window: &mut Window,
10718        cx: &mut Context<Self>,
10719    ) {
10720        let weak_editor = cx.weak_entity();
10721        let bp_prompt = cx.new(|cx| {
10722            BreakpointPromptEditor::new(
10723                weak_editor,
10724                anchor,
10725                breakpoint.clone(),
10726                edit_action,
10727                window,
10728                cx,
10729            )
10730        });
10731
10732        let height = bp_prompt.update(cx, |this, cx| {
10733            this.prompt
10734                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10735        });
10736        let cloned_prompt = bp_prompt.clone();
10737        let blocks = vec![BlockProperties {
10738            style: BlockStyle::Sticky,
10739            placement: BlockPlacement::Above(anchor),
10740            height: Some(height),
10741            render: Arc::new(move |cx| {
10742                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10743                cloned_prompt.clone().into_any_element()
10744            }),
10745            priority: 0,
10746        }];
10747
10748        let focus_handle = bp_prompt.focus_handle(cx);
10749        window.focus(&focus_handle);
10750
10751        let block_ids = self.insert_blocks(blocks, None, cx);
10752        bp_prompt.update(cx, |prompt, _| {
10753            prompt.add_block_ids(block_ids);
10754        });
10755    }
10756
10757    pub(crate) fn breakpoint_at_row(
10758        &self,
10759        row: u32,
10760        window: &mut Window,
10761        cx: &mut Context<Self>,
10762    ) -> Option<(Anchor, Breakpoint)> {
10763        let snapshot = self.snapshot(window, cx);
10764        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10765
10766        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10767    }
10768
10769    pub(crate) fn breakpoint_at_anchor(
10770        &self,
10771        breakpoint_position: Anchor,
10772        snapshot: &EditorSnapshot,
10773        cx: &mut Context<Self>,
10774    ) -> Option<(Anchor, Breakpoint)> {
10775        let buffer = self
10776            .buffer
10777            .read(cx)
10778            .buffer_for_anchor(breakpoint_position, cx)?;
10779
10780        let enclosing_excerpt = breakpoint_position.excerpt_id;
10781        let buffer_snapshot = buffer.read(cx).snapshot();
10782
10783        let row = buffer_snapshot
10784            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10785            .row;
10786
10787        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10788        let anchor_end = snapshot
10789            .buffer_snapshot
10790            .anchor_after(Point::new(row, line_len));
10791
10792        self.breakpoint_store
10793            .as_ref()?
10794            .read_with(cx, |breakpoint_store, cx| {
10795                breakpoint_store
10796                    .breakpoints(
10797                        &buffer,
10798                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10799                        &buffer_snapshot,
10800                        cx,
10801                    )
10802                    .next()
10803                    .and_then(|(bp, _)| {
10804                        let breakpoint_row = buffer_snapshot
10805                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10806                            .row;
10807
10808                        if breakpoint_row == row {
10809                            snapshot
10810                                .buffer_snapshot
10811                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10812                                .map(|position| (position, bp.bp.clone()))
10813                        } else {
10814                            None
10815                        }
10816                    })
10817            })
10818    }
10819
10820    pub fn edit_log_breakpoint(
10821        &mut self,
10822        _: &EditLogBreakpoint,
10823        window: &mut Window,
10824        cx: &mut Context<Self>,
10825    ) {
10826        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10827            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10828                message: None,
10829                state: BreakpointState::Enabled,
10830                condition: None,
10831                hit_condition: None,
10832            });
10833
10834            self.add_edit_breakpoint_block(
10835                anchor,
10836                &breakpoint,
10837                BreakpointPromptEditAction::Log,
10838                window,
10839                cx,
10840            );
10841        }
10842    }
10843
10844    fn breakpoints_at_cursors(
10845        &self,
10846        window: &mut Window,
10847        cx: &mut Context<Self>,
10848    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10849        let snapshot = self.snapshot(window, cx);
10850        let cursors = self
10851            .selections
10852            .disjoint_anchors_arc()
10853            .iter()
10854            .map(|selection| {
10855                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10856
10857                let breakpoint_position = self
10858                    .breakpoint_at_row(cursor_position.row, window, cx)
10859                    .map(|bp| bp.0)
10860                    .unwrap_or_else(|| {
10861                        snapshot
10862                            .display_snapshot
10863                            .buffer_snapshot
10864                            .anchor_after(Point::new(cursor_position.row, 0))
10865                    });
10866
10867                let breakpoint = self
10868                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10869                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10870
10871                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10872            })
10873            // 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.
10874            .collect::<HashMap<Anchor, _>>();
10875
10876        cursors.into_iter().collect()
10877    }
10878
10879    pub fn enable_breakpoint(
10880        &mut self,
10881        _: &crate::actions::EnableBreakpoint,
10882        window: &mut Window,
10883        cx: &mut Context<Self>,
10884    ) {
10885        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10886            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10887                continue;
10888            };
10889            self.edit_breakpoint_at_anchor(
10890                anchor,
10891                breakpoint,
10892                BreakpointEditAction::InvertState,
10893                cx,
10894            );
10895        }
10896    }
10897
10898    pub fn disable_breakpoint(
10899        &mut self,
10900        _: &crate::actions::DisableBreakpoint,
10901        window: &mut Window,
10902        cx: &mut Context<Self>,
10903    ) {
10904        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10905            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10906                continue;
10907            };
10908            self.edit_breakpoint_at_anchor(
10909                anchor,
10910                breakpoint,
10911                BreakpointEditAction::InvertState,
10912                cx,
10913            );
10914        }
10915    }
10916
10917    pub fn toggle_breakpoint(
10918        &mut self,
10919        _: &crate::actions::ToggleBreakpoint,
10920        window: &mut Window,
10921        cx: &mut Context<Self>,
10922    ) {
10923        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10924            if let Some(breakpoint) = breakpoint {
10925                self.edit_breakpoint_at_anchor(
10926                    anchor,
10927                    breakpoint,
10928                    BreakpointEditAction::Toggle,
10929                    cx,
10930                );
10931            } else {
10932                self.edit_breakpoint_at_anchor(
10933                    anchor,
10934                    Breakpoint::new_standard(),
10935                    BreakpointEditAction::Toggle,
10936                    cx,
10937                );
10938            }
10939        }
10940    }
10941
10942    pub fn edit_breakpoint_at_anchor(
10943        &mut self,
10944        breakpoint_position: Anchor,
10945        breakpoint: Breakpoint,
10946        edit_action: BreakpointEditAction,
10947        cx: &mut Context<Self>,
10948    ) {
10949        let Some(breakpoint_store) = &self.breakpoint_store else {
10950            return;
10951        };
10952
10953        let Some(buffer) = self
10954            .buffer
10955            .read(cx)
10956            .buffer_for_anchor(breakpoint_position, cx)
10957        else {
10958            return;
10959        };
10960
10961        breakpoint_store.update(cx, |breakpoint_store, cx| {
10962            breakpoint_store.toggle_breakpoint(
10963                buffer,
10964                BreakpointWithPosition {
10965                    position: breakpoint_position.text_anchor,
10966                    bp: breakpoint,
10967                },
10968                edit_action,
10969                cx,
10970            );
10971        });
10972
10973        cx.notify();
10974    }
10975
10976    #[cfg(any(test, feature = "test-support"))]
10977    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10978        self.breakpoint_store.clone()
10979    }
10980
10981    pub fn prepare_restore_change(
10982        &self,
10983        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10984        hunk: &MultiBufferDiffHunk,
10985        cx: &mut App,
10986    ) -> Option<()> {
10987        if hunk.is_created_file() {
10988            return None;
10989        }
10990        let buffer = self.buffer.read(cx);
10991        let diff = buffer.diff_for(hunk.buffer_id)?;
10992        let buffer = buffer.buffer(hunk.buffer_id)?;
10993        let buffer = buffer.read(cx);
10994        let original_text = diff
10995            .read(cx)
10996            .base_text()
10997            .as_rope()
10998            .slice(hunk.diff_base_byte_range.clone());
10999        let buffer_snapshot = buffer.snapshot();
11000        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11001        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11002            probe
11003                .0
11004                .start
11005                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11006                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11007        }) {
11008            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11009            Some(())
11010        } else {
11011            None
11012        }
11013    }
11014
11015    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11016        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11017    }
11018
11019    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11020        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11021    }
11022
11023    fn manipulate_lines<M>(
11024        &mut self,
11025        window: &mut Window,
11026        cx: &mut Context<Self>,
11027        mut manipulate: M,
11028    ) where
11029        M: FnMut(&str) -> LineManipulationResult,
11030    {
11031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11032
11033        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11034        let buffer = self.buffer.read(cx).snapshot(cx);
11035
11036        let mut edits = Vec::new();
11037
11038        let selections = self.selections.all::<Point>(cx);
11039        let mut selections = selections.iter().peekable();
11040        let mut contiguous_row_selections = Vec::new();
11041        let mut new_selections = Vec::new();
11042        let mut added_lines = 0;
11043        let mut removed_lines = 0;
11044
11045        while let Some(selection) = selections.next() {
11046            let (start_row, end_row) = consume_contiguous_rows(
11047                &mut contiguous_row_selections,
11048                selection,
11049                &display_map,
11050                &mut selections,
11051            );
11052
11053            let start_point = Point::new(start_row.0, 0);
11054            let end_point = Point::new(
11055                end_row.previous_row().0,
11056                buffer.line_len(end_row.previous_row()),
11057            );
11058            let text = buffer
11059                .text_for_range(start_point..end_point)
11060                .collect::<String>();
11061
11062            let LineManipulationResult {
11063                new_text,
11064                line_count_before,
11065                line_count_after,
11066            } = manipulate(&text);
11067
11068            edits.push((start_point..end_point, new_text));
11069
11070            // Selections must change based on added and removed line count
11071            let start_row =
11072                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11073            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11074            new_selections.push(Selection {
11075                id: selection.id,
11076                start: start_row,
11077                end: end_row,
11078                goal: SelectionGoal::None,
11079                reversed: selection.reversed,
11080            });
11081
11082            if line_count_after > line_count_before {
11083                added_lines += line_count_after - line_count_before;
11084            } else if line_count_before > line_count_after {
11085                removed_lines += line_count_before - line_count_after;
11086            }
11087        }
11088
11089        self.transact(window, cx, |this, window, cx| {
11090            let buffer = this.buffer.update(cx, |buffer, cx| {
11091                buffer.edit(edits, None, cx);
11092                buffer.snapshot(cx)
11093            });
11094
11095            // Recalculate offsets on newly edited buffer
11096            let new_selections = new_selections
11097                .iter()
11098                .map(|s| {
11099                    let start_point = Point::new(s.start.0, 0);
11100                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11101                    Selection {
11102                        id: s.id,
11103                        start: buffer.point_to_offset(start_point),
11104                        end: buffer.point_to_offset(end_point),
11105                        goal: s.goal,
11106                        reversed: s.reversed,
11107                    }
11108                })
11109                .collect();
11110
11111            this.change_selections(Default::default(), window, cx, |s| {
11112                s.select(new_selections);
11113            });
11114
11115            this.request_autoscroll(Autoscroll::fit(), cx);
11116        });
11117    }
11118
11119    fn manipulate_immutable_lines<Fn>(
11120        &mut self,
11121        window: &mut Window,
11122        cx: &mut Context<Self>,
11123        mut callback: Fn,
11124    ) where
11125        Fn: FnMut(&mut Vec<&str>),
11126    {
11127        self.manipulate_lines(window, cx, |text| {
11128            let mut lines: Vec<&str> = text.split('\n').collect();
11129            let line_count_before = lines.len();
11130
11131            callback(&mut lines);
11132
11133            LineManipulationResult {
11134                new_text: lines.join("\n"),
11135                line_count_before,
11136                line_count_after: lines.len(),
11137            }
11138        });
11139    }
11140
11141    fn manipulate_mutable_lines<Fn>(
11142        &mut self,
11143        window: &mut Window,
11144        cx: &mut Context<Self>,
11145        mut callback: Fn,
11146    ) where
11147        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11148    {
11149        self.manipulate_lines(window, cx, |text| {
11150            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11151            let line_count_before = lines.len();
11152
11153            callback(&mut lines);
11154
11155            LineManipulationResult {
11156                new_text: lines.join("\n"),
11157                line_count_before,
11158                line_count_after: lines.len(),
11159            }
11160        });
11161    }
11162
11163    pub fn convert_indentation_to_spaces(
11164        &mut self,
11165        _: &ConvertIndentationToSpaces,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        let settings = self.buffer.read(cx).language_settings(cx);
11170        let tab_size = settings.tab_size.get() as usize;
11171
11172        self.manipulate_mutable_lines(window, cx, |lines| {
11173            // Allocates a reasonably sized scratch buffer once for the whole loop
11174            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11175            // Avoids recomputing spaces that could be inserted many times
11176            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11177                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11178                .collect();
11179
11180            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11181                let mut chars = line.as_ref().chars();
11182                let mut col = 0;
11183                let mut changed = false;
11184
11185                for ch in chars.by_ref() {
11186                    match ch {
11187                        ' ' => {
11188                            reindented_line.push(' ');
11189                            col += 1;
11190                        }
11191                        '\t' => {
11192                            // \t are converted to spaces depending on the current column
11193                            let spaces_len = tab_size - (col % tab_size);
11194                            reindented_line.extend(&space_cache[spaces_len - 1]);
11195                            col += spaces_len;
11196                            changed = true;
11197                        }
11198                        _ => {
11199                            // If we dont append before break, the character is consumed
11200                            reindented_line.push(ch);
11201                            break;
11202                        }
11203                    }
11204                }
11205
11206                if !changed {
11207                    reindented_line.clear();
11208                    continue;
11209                }
11210                // Append the rest of the line and replace old reference with new one
11211                reindented_line.extend(chars);
11212                *line = Cow::Owned(reindented_line.clone());
11213                reindented_line.clear();
11214            }
11215        });
11216    }
11217
11218    pub fn convert_indentation_to_tabs(
11219        &mut self,
11220        _: &ConvertIndentationToTabs,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223    ) {
11224        let settings = self.buffer.read(cx).language_settings(cx);
11225        let tab_size = settings.tab_size.get() as usize;
11226
11227        self.manipulate_mutable_lines(window, cx, |lines| {
11228            // Allocates a reasonably sized buffer once for the whole loop
11229            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11230            // Avoids recomputing spaces that could be inserted many times
11231            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11232                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11233                .collect();
11234
11235            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11236                let mut chars = line.chars();
11237                let mut spaces_count = 0;
11238                let mut first_non_indent_char = None;
11239                let mut changed = false;
11240
11241                for ch in chars.by_ref() {
11242                    match ch {
11243                        ' ' => {
11244                            // Keep track of spaces. Append \t when we reach tab_size
11245                            spaces_count += 1;
11246                            changed = true;
11247                            if spaces_count == tab_size {
11248                                reindented_line.push('\t');
11249                                spaces_count = 0;
11250                            }
11251                        }
11252                        '\t' => {
11253                            reindented_line.push('\t');
11254                            spaces_count = 0;
11255                        }
11256                        _ => {
11257                            // Dont append it yet, we might have remaining spaces
11258                            first_non_indent_char = Some(ch);
11259                            break;
11260                        }
11261                    }
11262                }
11263
11264                if !changed {
11265                    reindented_line.clear();
11266                    continue;
11267                }
11268                // Remaining spaces that didn't make a full tab stop
11269                if spaces_count > 0 {
11270                    reindented_line.extend(&space_cache[spaces_count - 1]);
11271                }
11272                // If we consume an extra character that was not indentation, add it back
11273                if let Some(extra_char) = first_non_indent_char {
11274                    reindented_line.push(extra_char);
11275                }
11276                // Append the rest of the line and replace old reference with new one
11277                reindented_line.extend(chars);
11278                *line = Cow::Owned(reindented_line.clone());
11279                reindented_line.clear();
11280            }
11281        });
11282    }
11283
11284    pub fn convert_to_upper_case(
11285        &mut self,
11286        _: &ConvertToUpperCase,
11287        window: &mut Window,
11288        cx: &mut Context<Self>,
11289    ) {
11290        self.manipulate_text(window, cx, |text| text.to_uppercase())
11291    }
11292
11293    pub fn convert_to_lower_case(
11294        &mut self,
11295        _: &ConvertToLowerCase,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298    ) {
11299        self.manipulate_text(window, cx, |text| text.to_lowercase())
11300    }
11301
11302    pub fn convert_to_title_case(
11303        &mut self,
11304        _: &ConvertToTitleCase,
11305        window: &mut Window,
11306        cx: &mut Context<Self>,
11307    ) {
11308        self.manipulate_text(window, cx, |text| {
11309            text.split('\n')
11310                .map(|line| line.to_case(Case::Title))
11311                .join("\n")
11312        })
11313    }
11314
11315    pub fn convert_to_snake_case(
11316        &mut self,
11317        _: &ConvertToSnakeCase,
11318        window: &mut Window,
11319        cx: &mut Context<Self>,
11320    ) {
11321        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11322    }
11323
11324    pub fn convert_to_kebab_case(
11325        &mut self,
11326        _: &ConvertToKebabCase,
11327        window: &mut Window,
11328        cx: &mut Context<Self>,
11329    ) {
11330        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11331    }
11332
11333    pub fn convert_to_upper_camel_case(
11334        &mut self,
11335        _: &ConvertToUpperCamelCase,
11336        window: &mut Window,
11337        cx: &mut Context<Self>,
11338    ) {
11339        self.manipulate_text(window, cx, |text| {
11340            text.split('\n')
11341                .map(|line| line.to_case(Case::UpperCamel))
11342                .join("\n")
11343        })
11344    }
11345
11346    pub fn convert_to_lower_camel_case(
11347        &mut self,
11348        _: &ConvertToLowerCamelCase,
11349        window: &mut Window,
11350        cx: &mut Context<Self>,
11351    ) {
11352        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11353    }
11354
11355    pub fn convert_to_opposite_case(
11356        &mut self,
11357        _: &ConvertToOppositeCase,
11358        window: &mut Window,
11359        cx: &mut Context<Self>,
11360    ) {
11361        self.manipulate_text(window, cx, |text| {
11362            text.chars()
11363                .fold(String::with_capacity(text.len()), |mut t, c| {
11364                    if c.is_uppercase() {
11365                        t.extend(c.to_lowercase());
11366                    } else {
11367                        t.extend(c.to_uppercase());
11368                    }
11369                    t
11370                })
11371        })
11372    }
11373
11374    pub fn convert_to_sentence_case(
11375        &mut self,
11376        _: &ConvertToSentenceCase,
11377        window: &mut Window,
11378        cx: &mut Context<Self>,
11379    ) {
11380        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11381    }
11382
11383    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11384        self.manipulate_text(window, cx, |text| {
11385            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11386            if has_upper_case_characters {
11387                text.to_lowercase()
11388            } else {
11389                text.to_uppercase()
11390            }
11391        })
11392    }
11393
11394    pub fn convert_to_rot13(
11395        &mut self,
11396        _: &ConvertToRot13,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        self.manipulate_text(window, cx, |text| {
11401            text.chars()
11402                .map(|c| match c {
11403                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11404                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11405                    _ => c,
11406                })
11407                .collect()
11408        })
11409    }
11410
11411    pub fn convert_to_rot47(
11412        &mut self,
11413        _: &ConvertToRot47,
11414        window: &mut Window,
11415        cx: &mut Context<Self>,
11416    ) {
11417        self.manipulate_text(window, cx, |text| {
11418            text.chars()
11419                .map(|c| {
11420                    let code_point = c as u32;
11421                    if code_point >= 33 && code_point <= 126 {
11422                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11423                    }
11424                    c
11425                })
11426                .collect()
11427        })
11428    }
11429
11430    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11431    where
11432        Fn: FnMut(&str) -> String,
11433    {
11434        let buffer = self.buffer.read(cx).snapshot(cx);
11435
11436        let mut new_selections = Vec::new();
11437        let mut edits = Vec::new();
11438        let mut selection_adjustment = 0i32;
11439
11440        for selection in self.selections.all_adjusted(cx) {
11441            let selection_is_empty = selection.is_empty();
11442
11443            let (start, end) = if selection_is_empty {
11444                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11445                (word_range.start, word_range.end)
11446            } else {
11447                (
11448                    buffer.point_to_offset(selection.start),
11449                    buffer.point_to_offset(selection.end),
11450                )
11451            };
11452
11453            let text = buffer.text_for_range(start..end).collect::<String>();
11454            let old_length = text.len() as i32;
11455            let text = callback(&text);
11456
11457            new_selections.push(Selection {
11458                start: (start as i32 - selection_adjustment) as usize,
11459                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11460                goal: SelectionGoal::None,
11461                id: selection.id,
11462                reversed: selection.reversed,
11463            });
11464
11465            selection_adjustment += old_length - text.len() as i32;
11466
11467            edits.push((start..end, text));
11468        }
11469
11470        self.transact(window, cx, |this, window, cx| {
11471            this.buffer.update(cx, |buffer, cx| {
11472                buffer.edit(edits, None, cx);
11473            });
11474
11475            this.change_selections(Default::default(), window, cx, |s| {
11476                s.select(new_selections);
11477            });
11478
11479            this.request_autoscroll(Autoscroll::fit(), cx);
11480        });
11481    }
11482
11483    pub fn move_selection_on_drop(
11484        &mut self,
11485        selection: &Selection<Anchor>,
11486        target: DisplayPoint,
11487        is_cut: bool,
11488        window: &mut Window,
11489        cx: &mut Context<Self>,
11490    ) {
11491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11492        let buffer = &display_map.buffer_snapshot;
11493        let mut edits = Vec::new();
11494        let insert_point = display_map
11495            .clip_point(target, Bias::Left)
11496            .to_point(&display_map);
11497        let text = buffer
11498            .text_for_range(selection.start..selection.end)
11499            .collect::<String>();
11500        if is_cut {
11501            edits.push(((selection.start..selection.end), String::new()));
11502        }
11503        let insert_anchor = buffer.anchor_before(insert_point);
11504        edits.push(((insert_anchor..insert_anchor), text));
11505        let last_edit_start = insert_anchor.bias_left(buffer);
11506        let last_edit_end = insert_anchor.bias_right(buffer);
11507        self.transact(window, cx, |this, window, cx| {
11508            this.buffer.update(cx, |buffer, cx| {
11509                buffer.edit(edits, None, cx);
11510            });
11511            this.change_selections(Default::default(), window, cx, |s| {
11512                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11513            });
11514        });
11515    }
11516
11517    pub fn clear_selection_drag_state(&mut self) {
11518        self.selection_drag_state = SelectionDragState::None;
11519    }
11520
11521    pub fn duplicate(
11522        &mut self,
11523        upwards: bool,
11524        whole_lines: bool,
11525        window: &mut Window,
11526        cx: &mut Context<Self>,
11527    ) {
11528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11529
11530        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11531        let buffer = &display_map.buffer_snapshot;
11532        let selections = self.selections.all::<Point>(cx);
11533
11534        let mut edits = Vec::new();
11535        let mut selections_iter = selections.iter().peekable();
11536        while let Some(selection) = selections_iter.next() {
11537            let mut rows = selection.spanned_rows(false, &display_map);
11538            // duplicate line-wise
11539            if whole_lines || selection.start == selection.end {
11540                // Avoid duplicating the same lines twice.
11541                while let Some(next_selection) = selections_iter.peek() {
11542                    let next_rows = next_selection.spanned_rows(false, &display_map);
11543                    if next_rows.start < rows.end {
11544                        rows.end = next_rows.end;
11545                        selections_iter.next().unwrap();
11546                    } else {
11547                        break;
11548                    }
11549                }
11550
11551                // Copy the text from the selected row region and splice it either at the start
11552                // or end of the region.
11553                let start = Point::new(rows.start.0, 0);
11554                let end = Point::new(
11555                    rows.end.previous_row().0,
11556                    buffer.line_len(rows.end.previous_row()),
11557                );
11558                let text = buffer
11559                    .text_for_range(start..end)
11560                    .chain(Some("\n"))
11561                    .collect::<String>();
11562                let insert_location = if upwards {
11563                    Point::new(rows.end.0, 0)
11564                } else {
11565                    start
11566                };
11567                edits.push((insert_location..insert_location, text));
11568            } else {
11569                // duplicate character-wise
11570                let start = selection.start;
11571                let end = selection.end;
11572                let text = buffer.text_for_range(start..end).collect::<String>();
11573                edits.push((selection.end..selection.end, text));
11574            }
11575        }
11576
11577        self.transact(window, cx, |this, _, cx| {
11578            this.buffer.update(cx, |buffer, cx| {
11579                buffer.edit(edits, None, cx);
11580            });
11581
11582            this.request_autoscroll(Autoscroll::fit(), cx);
11583        });
11584    }
11585
11586    pub fn duplicate_line_up(
11587        &mut self,
11588        _: &DuplicateLineUp,
11589        window: &mut Window,
11590        cx: &mut Context<Self>,
11591    ) {
11592        self.duplicate(true, true, window, cx);
11593    }
11594
11595    pub fn duplicate_line_down(
11596        &mut self,
11597        _: &DuplicateLineDown,
11598        window: &mut Window,
11599        cx: &mut Context<Self>,
11600    ) {
11601        self.duplicate(false, true, window, cx);
11602    }
11603
11604    pub fn duplicate_selection(
11605        &mut self,
11606        _: &DuplicateSelection,
11607        window: &mut Window,
11608        cx: &mut Context<Self>,
11609    ) {
11610        self.duplicate(false, false, window, cx);
11611    }
11612
11613    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11614        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11615        if self.mode.is_single_line() {
11616            cx.propagate();
11617            return;
11618        }
11619
11620        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11621        let buffer = self.buffer.read(cx).snapshot(cx);
11622
11623        let mut edits = Vec::new();
11624        let mut unfold_ranges = Vec::new();
11625        let mut refold_creases = Vec::new();
11626
11627        let selections = self.selections.all::<Point>(cx);
11628        let mut selections = selections.iter().peekable();
11629        let mut contiguous_row_selections = Vec::new();
11630        let mut new_selections = Vec::new();
11631
11632        while let Some(selection) = selections.next() {
11633            // Find all the selections that span a contiguous row range
11634            let (start_row, end_row) = consume_contiguous_rows(
11635                &mut contiguous_row_selections,
11636                selection,
11637                &display_map,
11638                &mut selections,
11639            );
11640
11641            // Move the text spanned by the row range to be before the line preceding the row range
11642            if start_row.0 > 0 {
11643                let range_to_move = Point::new(
11644                    start_row.previous_row().0,
11645                    buffer.line_len(start_row.previous_row()),
11646                )
11647                    ..Point::new(
11648                        end_row.previous_row().0,
11649                        buffer.line_len(end_row.previous_row()),
11650                    );
11651                let insertion_point = display_map
11652                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11653                    .0;
11654
11655                // Don't move lines across excerpts
11656                if buffer
11657                    .excerpt_containing(insertion_point..range_to_move.end)
11658                    .is_some()
11659                {
11660                    let text = buffer
11661                        .text_for_range(range_to_move.clone())
11662                        .flat_map(|s| s.chars())
11663                        .skip(1)
11664                        .chain(['\n'])
11665                        .collect::<String>();
11666
11667                    edits.push((
11668                        buffer.anchor_after(range_to_move.start)
11669                            ..buffer.anchor_before(range_to_move.end),
11670                        String::new(),
11671                    ));
11672                    let insertion_anchor = buffer.anchor_after(insertion_point);
11673                    edits.push((insertion_anchor..insertion_anchor, text));
11674
11675                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11676
11677                    // Move selections up
11678                    new_selections.extend(contiguous_row_selections.drain(..).map(
11679                        |mut selection| {
11680                            selection.start.row -= row_delta;
11681                            selection.end.row -= row_delta;
11682                            selection
11683                        },
11684                    ));
11685
11686                    // Move folds up
11687                    unfold_ranges.push(range_to_move.clone());
11688                    for fold in display_map.folds_in_range(
11689                        buffer.anchor_before(range_to_move.start)
11690                            ..buffer.anchor_after(range_to_move.end),
11691                    ) {
11692                        let mut start = fold.range.start.to_point(&buffer);
11693                        let mut end = fold.range.end.to_point(&buffer);
11694                        start.row -= row_delta;
11695                        end.row -= row_delta;
11696                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11697                    }
11698                }
11699            }
11700
11701            // If we didn't move line(s), preserve the existing selections
11702            new_selections.append(&mut contiguous_row_selections);
11703        }
11704
11705        self.transact(window, cx, |this, window, cx| {
11706            this.unfold_ranges(&unfold_ranges, true, true, cx);
11707            this.buffer.update(cx, |buffer, cx| {
11708                for (range, text) in edits {
11709                    buffer.edit([(range, text)], None, cx);
11710                }
11711            });
11712            this.fold_creases(refold_creases, true, window, cx);
11713            this.change_selections(Default::default(), window, cx, |s| {
11714                s.select(new_selections);
11715            })
11716        });
11717    }
11718
11719    pub fn move_line_down(
11720        &mut self,
11721        _: &MoveLineDown,
11722        window: &mut Window,
11723        cx: &mut Context<Self>,
11724    ) {
11725        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11726        if self.mode.is_single_line() {
11727            cx.propagate();
11728            return;
11729        }
11730
11731        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11732        let buffer = self.buffer.read(cx).snapshot(cx);
11733
11734        let mut edits = Vec::new();
11735        let mut unfold_ranges = Vec::new();
11736        let mut refold_creases = Vec::new();
11737
11738        let selections = self.selections.all::<Point>(cx);
11739        let mut selections = selections.iter().peekable();
11740        let mut contiguous_row_selections = Vec::new();
11741        let mut new_selections = Vec::new();
11742
11743        while let Some(selection) = selections.next() {
11744            // Find all the selections that span a contiguous row range
11745            let (start_row, end_row) = consume_contiguous_rows(
11746                &mut contiguous_row_selections,
11747                selection,
11748                &display_map,
11749                &mut selections,
11750            );
11751
11752            // Move the text spanned by the row range to be after the last line of the row range
11753            if end_row.0 <= buffer.max_point().row {
11754                let range_to_move =
11755                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11756                let insertion_point = display_map
11757                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11758                    .0;
11759
11760                // Don't move lines across excerpt boundaries
11761                if buffer
11762                    .excerpt_containing(range_to_move.start..insertion_point)
11763                    .is_some()
11764                {
11765                    let mut text = String::from("\n");
11766                    text.extend(buffer.text_for_range(range_to_move.clone()));
11767                    text.pop(); // Drop trailing newline
11768                    edits.push((
11769                        buffer.anchor_after(range_to_move.start)
11770                            ..buffer.anchor_before(range_to_move.end),
11771                        String::new(),
11772                    ));
11773                    let insertion_anchor = buffer.anchor_after(insertion_point);
11774                    edits.push((insertion_anchor..insertion_anchor, text));
11775
11776                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11777
11778                    // Move selections down
11779                    new_selections.extend(contiguous_row_selections.drain(..).map(
11780                        |mut selection| {
11781                            selection.start.row += row_delta;
11782                            selection.end.row += row_delta;
11783                            selection
11784                        },
11785                    ));
11786
11787                    // Move folds down
11788                    unfold_ranges.push(range_to_move.clone());
11789                    for fold in display_map.folds_in_range(
11790                        buffer.anchor_before(range_to_move.start)
11791                            ..buffer.anchor_after(range_to_move.end),
11792                    ) {
11793                        let mut start = fold.range.start.to_point(&buffer);
11794                        let mut end = fold.range.end.to_point(&buffer);
11795                        start.row += row_delta;
11796                        end.row += row_delta;
11797                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11798                    }
11799                }
11800            }
11801
11802            // If we didn't move line(s), preserve the existing selections
11803            new_selections.append(&mut contiguous_row_selections);
11804        }
11805
11806        self.transact(window, cx, |this, window, cx| {
11807            this.unfold_ranges(&unfold_ranges, true, true, cx);
11808            this.buffer.update(cx, |buffer, cx| {
11809                for (range, text) in edits {
11810                    buffer.edit([(range, text)], None, cx);
11811                }
11812            });
11813            this.fold_creases(refold_creases, true, window, cx);
11814            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11815        });
11816    }
11817
11818    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11820        let text_layout_details = &self.text_layout_details(window);
11821        self.transact(window, cx, |this, window, cx| {
11822            let edits = this.change_selections(Default::default(), window, cx, |s| {
11823                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11824                s.move_with(|display_map, selection| {
11825                    if !selection.is_empty() {
11826                        return;
11827                    }
11828
11829                    let mut head = selection.head();
11830                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11831                    if head.column() == display_map.line_len(head.row()) {
11832                        transpose_offset = display_map
11833                            .buffer_snapshot
11834                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11835                    }
11836
11837                    if transpose_offset == 0 {
11838                        return;
11839                    }
11840
11841                    *head.column_mut() += 1;
11842                    head = display_map.clip_point(head, Bias::Right);
11843                    let goal = SelectionGoal::HorizontalPosition(
11844                        display_map
11845                            .x_for_display_point(head, text_layout_details)
11846                            .into(),
11847                    );
11848                    selection.collapse_to(head, goal);
11849
11850                    let transpose_start = display_map
11851                        .buffer_snapshot
11852                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11853                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11854                        let transpose_end = display_map
11855                            .buffer_snapshot
11856                            .clip_offset(transpose_offset + 1, Bias::Right);
11857                        if let Some(ch) =
11858                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11859                        {
11860                            edits.push((transpose_start..transpose_offset, String::new()));
11861                            edits.push((transpose_end..transpose_end, ch.to_string()));
11862                        }
11863                    }
11864                });
11865                edits
11866            });
11867            this.buffer
11868                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11869            let selections = this.selections.all::<usize>(cx);
11870            this.change_selections(Default::default(), window, cx, |s| {
11871                s.select(selections);
11872            });
11873        });
11874    }
11875
11876    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11878        if self.mode.is_single_line() {
11879            cx.propagate();
11880            return;
11881        }
11882
11883        self.rewrap_impl(RewrapOptions::default(), cx)
11884    }
11885
11886    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11887        let buffer = self.buffer.read(cx).snapshot(cx);
11888        let selections = self.selections.all::<Point>(cx);
11889
11890        #[derive(Clone, Debug, PartialEq)]
11891        enum CommentFormat {
11892            /// single line comment, with prefix for line
11893            Line(String),
11894            /// single line within a block comment, with prefix for line
11895            BlockLine(String),
11896            /// a single line of a block comment that includes the initial delimiter
11897            BlockCommentWithStart(BlockCommentConfig),
11898            /// a single line of a block comment that includes the ending delimiter
11899            BlockCommentWithEnd(BlockCommentConfig),
11900        }
11901
11902        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11903        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11904            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11905                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11906                .peekable();
11907
11908            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11909                row
11910            } else {
11911                return Vec::new();
11912            };
11913
11914            let language_settings = buffer.language_settings_at(selection.head(), cx);
11915            let language_scope = buffer.language_scope_at(selection.head());
11916
11917            let indent_and_prefix_for_row =
11918                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11919                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11920                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11921                        &language_scope
11922                    {
11923                        let indent_end = Point::new(row, indent.len);
11924                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11925                        let line_text_after_indent = buffer
11926                            .text_for_range(indent_end..line_end)
11927                            .collect::<String>();
11928
11929                        let is_within_comment_override = buffer
11930                            .language_scope_at(indent_end)
11931                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11932                        let comment_delimiters = if is_within_comment_override {
11933                            // we are within a comment syntax node, but we don't
11934                            // yet know what kind of comment: block, doc or line
11935                            match (
11936                                language_scope.documentation_comment(),
11937                                language_scope.block_comment(),
11938                            ) {
11939                                (Some(config), _) | (_, Some(config))
11940                                    if buffer.contains_str_at(indent_end, &config.start) =>
11941                                {
11942                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11943                                }
11944                                (Some(config), _) | (_, Some(config))
11945                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11946                                {
11947                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11948                                }
11949                                (Some(config), _) | (_, Some(config))
11950                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11951                                {
11952                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11953                                }
11954                                (_, _) => language_scope
11955                                    .line_comment_prefixes()
11956                                    .iter()
11957                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11958                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11959                            }
11960                        } else {
11961                            // we not in an overridden comment node, but we may
11962                            // be within a non-overridden line comment node
11963                            language_scope
11964                                .line_comment_prefixes()
11965                                .iter()
11966                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11967                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11968                        };
11969
11970                        let rewrap_prefix = language_scope
11971                            .rewrap_prefixes()
11972                            .iter()
11973                            .find_map(|prefix_regex| {
11974                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11975                                    if mat.start() == 0 {
11976                                        Some(mat.as_str().to_string())
11977                                    } else {
11978                                        None
11979                                    }
11980                                })
11981                            })
11982                            .flatten();
11983                        (comment_delimiters, rewrap_prefix)
11984                    } else {
11985                        (None, None)
11986                    };
11987                    (indent, comment_prefix, rewrap_prefix)
11988                };
11989
11990            let mut ranges = Vec::new();
11991            let from_empty_selection = selection.is_empty();
11992
11993            let mut current_range_start = first_row;
11994            let mut prev_row = first_row;
11995            let (
11996                mut current_range_indent,
11997                mut current_range_comment_delimiters,
11998                mut current_range_rewrap_prefix,
11999            ) = indent_and_prefix_for_row(first_row);
12000
12001            for row in non_blank_rows_iter.skip(1) {
12002                let has_paragraph_break = row > prev_row + 1;
12003
12004                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12005                    indent_and_prefix_for_row(row);
12006
12007                let has_indent_change = row_indent != current_range_indent;
12008                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12009
12010                let has_boundary_change = has_comment_change
12011                    || row_rewrap_prefix.is_some()
12012                    || (has_indent_change && current_range_comment_delimiters.is_some());
12013
12014                if has_paragraph_break || has_boundary_change {
12015                    ranges.push((
12016                        language_settings.clone(),
12017                        Point::new(current_range_start, 0)
12018                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12019                        current_range_indent,
12020                        current_range_comment_delimiters.clone(),
12021                        current_range_rewrap_prefix.clone(),
12022                        from_empty_selection,
12023                    ));
12024                    current_range_start = row;
12025                    current_range_indent = row_indent;
12026                    current_range_comment_delimiters = row_comment_delimiters;
12027                    current_range_rewrap_prefix = row_rewrap_prefix;
12028                }
12029                prev_row = row;
12030            }
12031
12032            ranges.push((
12033                language_settings.clone(),
12034                Point::new(current_range_start, 0)
12035                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12036                current_range_indent,
12037                current_range_comment_delimiters,
12038                current_range_rewrap_prefix,
12039                from_empty_selection,
12040            ));
12041
12042            ranges
12043        });
12044
12045        let mut edits = Vec::new();
12046        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12047
12048        for (
12049            language_settings,
12050            wrap_range,
12051            mut indent_size,
12052            comment_prefix,
12053            rewrap_prefix,
12054            from_empty_selection,
12055        ) in wrap_ranges
12056        {
12057            let mut start_row = wrap_range.start.row;
12058            let mut end_row = wrap_range.end.row;
12059
12060            // Skip selections that overlap with a range that has already been rewrapped.
12061            let selection_range = start_row..end_row;
12062            if rewrapped_row_ranges
12063                .iter()
12064                .any(|range| range.overlaps(&selection_range))
12065            {
12066                continue;
12067            }
12068
12069            let tab_size = language_settings.tab_size;
12070
12071            let (line_prefix, inside_comment) = match &comment_prefix {
12072                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12073                    (Some(prefix.as_str()), true)
12074                }
12075                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12076                    (Some(prefix.as_ref()), true)
12077                }
12078                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12079                    start: _,
12080                    end: _,
12081                    prefix,
12082                    tab_size,
12083                })) => {
12084                    indent_size.len += tab_size;
12085                    (Some(prefix.as_ref()), true)
12086                }
12087                None => (None, false),
12088            };
12089            let indent_prefix = indent_size.chars().collect::<String>();
12090            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12091
12092            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12093                RewrapBehavior::InComments => inside_comment,
12094                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12095                RewrapBehavior::Anywhere => true,
12096            };
12097
12098            let should_rewrap = options.override_language_settings
12099                || allow_rewrap_based_on_language
12100                || self.hard_wrap.is_some();
12101            if !should_rewrap {
12102                continue;
12103            }
12104
12105            if from_empty_selection {
12106                'expand_upwards: while start_row > 0 {
12107                    let prev_row = start_row - 1;
12108                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12109                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12110                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12111                    {
12112                        start_row = prev_row;
12113                    } else {
12114                        break 'expand_upwards;
12115                    }
12116                }
12117
12118                'expand_downwards: while end_row < buffer.max_point().row {
12119                    let next_row = end_row + 1;
12120                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12121                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12122                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12123                    {
12124                        end_row = next_row;
12125                    } else {
12126                        break 'expand_downwards;
12127                    }
12128                }
12129            }
12130
12131            let start = Point::new(start_row, 0);
12132            let start_offset = start.to_offset(&buffer);
12133            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12134            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12135            let mut first_line_delimiter = None;
12136            let mut last_line_delimiter = None;
12137            let Some(lines_without_prefixes) = selection_text
12138                .lines()
12139                .enumerate()
12140                .map(|(ix, line)| {
12141                    let line_trimmed = line.trim_start();
12142                    if rewrap_prefix.is_some() && ix > 0 {
12143                        Ok(line_trimmed)
12144                    } else if let Some(
12145                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12146                            start,
12147                            prefix,
12148                            end,
12149                            tab_size,
12150                        })
12151                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12152                            start,
12153                            prefix,
12154                            end,
12155                            tab_size,
12156                        }),
12157                    ) = &comment_prefix
12158                    {
12159                        let line_trimmed = line_trimmed
12160                            .strip_prefix(start.as_ref())
12161                            .map(|s| {
12162                                let mut indent_size = indent_size;
12163                                indent_size.len -= tab_size;
12164                                let indent_prefix: String = indent_size.chars().collect();
12165                                first_line_delimiter = Some((indent_prefix, start));
12166                                s.trim_start()
12167                            })
12168                            .unwrap_or(line_trimmed);
12169                        let line_trimmed = line_trimmed
12170                            .strip_suffix(end.as_ref())
12171                            .map(|s| {
12172                                last_line_delimiter = Some(end);
12173                                s.trim_end()
12174                            })
12175                            .unwrap_or(line_trimmed);
12176                        let line_trimmed = line_trimmed
12177                            .strip_prefix(prefix.as_ref())
12178                            .unwrap_or(line_trimmed);
12179                        Ok(line_trimmed)
12180                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12181                        line_trimmed.strip_prefix(prefix).with_context(|| {
12182                            format!("line did not start with prefix {prefix:?}: {line:?}")
12183                        })
12184                    } else {
12185                        line_trimmed
12186                            .strip_prefix(&line_prefix.trim_start())
12187                            .with_context(|| {
12188                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12189                            })
12190                    }
12191                })
12192                .collect::<Result<Vec<_>, _>>()
12193                .log_err()
12194            else {
12195                continue;
12196            };
12197
12198            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12199                buffer
12200                    .language_settings_at(Point::new(start_row, 0), cx)
12201                    .preferred_line_length as usize
12202            });
12203
12204            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12205                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12206            } else {
12207                line_prefix.clone()
12208            };
12209
12210            let wrapped_text = {
12211                let mut wrapped_text = wrap_with_prefix(
12212                    line_prefix,
12213                    subsequent_lines_prefix,
12214                    lines_without_prefixes.join("\n"),
12215                    wrap_column,
12216                    tab_size,
12217                    options.preserve_existing_whitespace,
12218                );
12219
12220                if let Some((indent, delimiter)) = first_line_delimiter {
12221                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12222                }
12223                if let Some(last_line) = last_line_delimiter {
12224                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12225                }
12226
12227                wrapped_text
12228            };
12229
12230            // TODO: should always use char-based diff while still supporting cursor behavior that
12231            // matches vim.
12232            let mut diff_options = DiffOptions::default();
12233            if options.override_language_settings {
12234                diff_options.max_word_diff_len = 0;
12235                diff_options.max_word_diff_line_count = 0;
12236            } else {
12237                diff_options.max_word_diff_len = usize::MAX;
12238                diff_options.max_word_diff_line_count = usize::MAX;
12239            }
12240
12241            for (old_range, new_text) in
12242                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12243            {
12244                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12245                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12246                edits.push((edit_start..edit_end, new_text));
12247            }
12248
12249            rewrapped_row_ranges.push(start_row..=end_row);
12250        }
12251
12252        self.buffer
12253            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12254    }
12255
12256    pub fn cut_common(
12257        &mut self,
12258        cut_no_selection_line: bool,
12259        window: &mut Window,
12260        cx: &mut Context<Self>,
12261    ) -> ClipboardItem {
12262        let mut text = String::new();
12263        let buffer = self.buffer.read(cx).snapshot(cx);
12264        let mut selections = self.selections.all::<Point>(cx);
12265        let mut clipboard_selections = Vec::with_capacity(selections.len());
12266        {
12267            let max_point = buffer.max_point();
12268            let mut is_first = true;
12269            for selection in &mut selections {
12270                let is_entire_line =
12271                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12272                if is_entire_line {
12273                    selection.start = Point::new(selection.start.row, 0);
12274                    if !selection.is_empty() && selection.end.column == 0 {
12275                        selection.end = cmp::min(max_point, selection.end);
12276                    } else {
12277                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12278                    }
12279                    selection.goal = SelectionGoal::None;
12280                }
12281                if is_first {
12282                    is_first = false;
12283                } else {
12284                    text += "\n";
12285                }
12286                let mut len = 0;
12287                for chunk in buffer.text_for_range(selection.start..selection.end) {
12288                    text.push_str(chunk);
12289                    len += chunk.len();
12290                }
12291                clipboard_selections.push(ClipboardSelection {
12292                    len,
12293                    is_entire_line,
12294                    first_line_indent: buffer
12295                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12296                        .len,
12297                });
12298            }
12299        }
12300
12301        self.transact(window, cx, |this, window, cx| {
12302            this.change_selections(Default::default(), window, cx, |s| {
12303                s.select(selections);
12304            });
12305            this.insert("", window, cx);
12306        });
12307        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12308    }
12309
12310    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12312        let item = self.cut_common(true, window, cx);
12313        cx.write_to_clipboard(item);
12314    }
12315
12316    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12318        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12319            s.move_with(|snapshot, sel| {
12320                if sel.is_empty() {
12321                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12322                }
12323                if sel.is_empty() {
12324                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12325                }
12326            });
12327        });
12328        let item = self.cut_common(true, window, cx);
12329        cx.set_global(KillRing(item))
12330    }
12331
12332    pub fn kill_ring_yank(
12333        &mut self,
12334        _: &KillRingYank,
12335        window: &mut Window,
12336        cx: &mut Context<Self>,
12337    ) {
12338        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12339        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12340            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12341                (kill_ring.text().to_string(), kill_ring.metadata_json())
12342            } else {
12343                return;
12344            }
12345        } else {
12346            return;
12347        };
12348        self.do_paste(&text, metadata, false, window, cx);
12349    }
12350
12351    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12352        self.do_copy(true, cx);
12353    }
12354
12355    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12356        self.do_copy(false, cx);
12357    }
12358
12359    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12360        let selections = self.selections.all::<Point>(cx);
12361        let buffer = self.buffer.read(cx).read(cx);
12362        let mut text = String::new();
12363
12364        let mut clipboard_selections = Vec::with_capacity(selections.len());
12365        {
12366            let max_point = buffer.max_point();
12367            let mut is_first = true;
12368            for selection in &selections {
12369                let mut start = selection.start;
12370                let mut end = selection.end;
12371                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12372                if is_entire_line {
12373                    start = Point::new(start.row, 0);
12374                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12375                }
12376
12377                let mut trimmed_selections = Vec::new();
12378                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12379                    let row = MultiBufferRow(start.row);
12380                    let first_indent = buffer.indent_size_for_line(row);
12381                    if first_indent.len == 0 || start.column > first_indent.len {
12382                        trimmed_selections.push(start..end);
12383                    } else {
12384                        trimmed_selections.push(
12385                            Point::new(row.0, first_indent.len)
12386                                ..Point::new(row.0, buffer.line_len(row)),
12387                        );
12388                        for row in start.row + 1..=end.row {
12389                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12390                            if row == end.row {
12391                                line_len = end.column;
12392                            }
12393                            if line_len == 0 {
12394                                trimmed_selections
12395                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12396                                continue;
12397                            }
12398                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12399                            if row_indent_size.len >= first_indent.len {
12400                                trimmed_selections.push(
12401                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12402                                );
12403                            } else {
12404                                trimmed_selections.clear();
12405                                trimmed_selections.push(start..end);
12406                                break;
12407                            }
12408                        }
12409                    }
12410                } else {
12411                    trimmed_selections.push(start..end);
12412                }
12413
12414                for trimmed_range in trimmed_selections {
12415                    if is_first {
12416                        is_first = false;
12417                    } else {
12418                        text += "\n";
12419                    }
12420                    let mut len = 0;
12421                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12422                        text.push_str(chunk);
12423                        len += chunk.len();
12424                    }
12425                    clipboard_selections.push(ClipboardSelection {
12426                        len,
12427                        is_entire_line,
12428                        first_line_indent: buffer
12429                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12430                            .len,
12431                    });
12432                }
12433            }
12434        }
12435
12436        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12437            text,
12438            clipboard_selections,
12439        ));
12440    }
12441
12442    pub fn do_paste(
12443        &mut self,
12444        text: &String,
12445        clipboard_selections: Option<Vec<ClipboardSelection>>,
12446        handle_entire_lines: bool,
12447        window: &mut Window,
12448        cx: &mut Context<Self>,
12449    ) {
12450        if self.read_only(cx) {
12451            return;
12452        }
12453
12454        let clipboard_text = Cow::Borrowed(text);
12455
12456        self.transact(window, cx, |this, window, cx| {
12457            let had_active_edit_prediction = this.has_active_edit_prediction();
12458
12459            if let Some(mut clipboard_selections) = clipboard_selections {
12460                let old_selections = this.selections.all::<usize>(cx);
12461                let all_selections_were_entire_line =
12462                    clipboard_selections.iter().all(|s| s.is_entire_line);
12463                let first_selection_indent_column =
12464                    clipboard_selections.first().map(|s| s.first_line_indent);
12465                if clipboard_selections.len() != old_selections.len() {
12466                    clipboard_selections.drain(..);
12467                }
12468                let cursor_offset = this.selections.last::<usize>(cx).head();
12469                let mut auto_indent_on_paste = true;
12470
12471                this.buffer.update(cx, |buffer, cx| {
12472                    let snapshot = buffer.read(cx);
12473                    auto_indent_on_paste = snapshot
12474                        .language_settings_at(cursor_offset, cx)
12475                        .auto_indent_on_paste;
12476
12477                    let mut start_offset = 0;
12478                    let mut edits = Vec::new();
12479                    let mut original_indent_columns = Vec::new();
12480                    for (ix, selection) in old_selections.iter().enumerate() {
12481                        let to_insert;
12482                        let entire_line;
12483                        let original_indent_column;
12484                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12485                            let end_offset = start_offset + clipboard_selection.len;
12486                            to_insert = &clipboard_text[start_offset..end_offset];
12487                            entire_line = clipboard_selection.is_entire_line;
12488                            start_offset = end_offset + 1;
12489                            original_indent_column = Some(clipboard_selection.first_line_indent);
12490                        } else {
12491                            to_insert = clipboard_text.as_str();
12492                            entire_line = all_selections_were_entire_line;
12493                            original_indent_column = first_selection_indent_column
12494                        }
12495
12496                        // If the corresponding selection was empty when this slice of the
12497                        // clipboard text was written, then the entire line containing the
12498                        // selection was copied. If this selection is also currently empty,
12499                        // then paste the line before the current line of the buffer.
12500                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12501                            let column = selection.start.to_point(&snapshot).column as usize;
12502                            let line_start = selection.start - column;
12503                            line_start..line_start
12504                        } else {
12505                            selection.range()
12506                        };
12507
12508                        edits.push((range, to_insert));
12509                        original_indent_columns.push(original_indent_column);
12510                    }
12511                    drop(snapshot);
12512
12513                    buffer.edit(
12514                        edits,
12515                        if auto_indent_on_paste {
12516                            Some(AutoindentMode::Block {
12517                                original_indent_columns,
12518                            })
12519                        } else {
12520                            None
12521                        },
12522                        cx,
12523                    );
12524                });
12525
12526                let selections = this.selections.all::<usize>(cx);
12527                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12528            } else {
12529                this.insert(&clipboard_text, window, cx);
12530            }
12531
12532            let trigger_in_words =
12533                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12534
12535            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12536        });
12537    }
12538
12539    pub fn diff_clipboard_with_selection(
12540        &mut self,
12541        _: &DiffClipboardWithSelection,
12542        window: &mut Window,
12543        cx: &mut Context<Self>,
12544    ) {
12545        let selections = self.selections.all::<usize>(cx);
12546
12547        if selections.is_empty() {
12548            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12549            return;
12550        };
12551
12552        let clipboard_text = match cx.read_from_clipboard() {
12553            Some(item) => match item.entries().first() {
12554                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12555                _ => None,
12556            },
12557            None => None,
12558        };
12559
12560        let Some(clipboard_text) = clipboard_text else {
12561            log::warn!("Clipboard doesn't contain text.");
12562            return;
12563        };
12564
12565        window.dispatch_action(
12566            Box::new(DiffClipboardWithSelectionData {
12567                clipboard_text,
12568                editor: cx.entity(),
12569            }),
12570            cx,
12571        );
12572    }
12573
12574    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12576        if let Some(item) = cx.read_from_clipboard() {
12577            let entries = item.entries();
12578
12579            match entries.first() {
12580                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12581                // of all the pasted entries.
12582                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12583                    .do_paste(
12584                        clipboard_string.text(),
12585                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12586                        true,
12587                        window,
12588                        cx,
12589                    ),
12590                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12591            }
12592        }
12593    }
12594
12595    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12596        if self.read_only(cx) {
12597            return;
12598        }
12599
12600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12601
12602        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12603            if let Some((selections, _)) =
12604                self.selection_history.transaction(transaction_id).cloned()
12605            {
12606                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12607                    s.select_anchors(selections.to_vec());
12608                });
12609            } else {
12610                log::error!(
12611                    "No entry in selection_history found for undo. \
12612                     This may correspond to a bug where undo does not update the selection. \
12613                     If this is occurring, please add details to \
12614                     https://github.com/zed-industries/zed/issues/22692"
12615                );
12616            }
12617            self.request_autoscroll(Autoscroll::fit(), cx);
12618            self.unmark_text(window, cx);
12619            self.refresh_edit_prediction(true, false, window, cx);
12620            cx.emit(EditorEvent::Edited { transaction_id });
12621            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12622        }
12623    }
12624
12625    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12626        if self.read_only(cx) {
12627            return;
12628        }
12629
12630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12631
12632        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12633            if let Some((_, Some(selections))) =
12634                self.selection_history.transaction(transaction_id).cloned()
12635            {
12636                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12637                    s.select_anchors(selections.to_vec());
12638                });
12639            } else {
12640                log::error!(
12641                    "No entry in selection_history found for redo. \
12642                     This may correspond to a bug where undo does not update the selection. \
12643                     If this is occurring, please add details to \
12644                     https://github.com/zed-industries/zed/issues/22692"
12645                );
12646            }
12647            self.request_autoscroll(Autoscroll::fit(), cx);
12648            self.unmark_text(window, cx);
12649            self.refresh_edit_prediction(true, false, window, cx);
12650            cx.emit(EditorEvent::Edited { transaction_id });
12651        }
12652    }
12653
12654    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12655        self.buffer
12656            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12657    }
12658
12659    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12660        self.buffer
12661            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12662    }
12663
12664    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12666        self.change_selections(Default::default(), window, cx, |s| {
12667            s.move_with(|map, selection| {
12668                let cursor = if selection.is_empty() {
12669                    movement::left(map, selection.start)
12670                } else {
12671                    selection.start
12672                };
12673                selection.collapse_to(cursor, SelectionGoal::None);
12674            });
12675        })
12676    }
12677
12678    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680        self.change_selections(Default::default(), window, cx, |s| {
12681            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12682        })
12683    }
12684
12685    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12687        self.change_selections(Default::default(), window, cx, |s| {
12688            s.move_with(|map, selection| {
12689                let cursor = if selection.is_empty() {
12690                    movement::right(map, selection.end)
12691                } else {
12692                    selection.end
12693                };
12694                selection.collapse_to(cursor, SelectionGoal::None)
12695            });
12696        })
12697    }
12698
12699    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12701        self.change_selections(Default::default(), window, cx, |s| {
12702            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12703        })
12704    }
12705
12706    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12707        if self.take_rename(true, window, cx).is_some() {
12708            return;
12709        }
12710
12711        if self.mode.is_single_line() {
12712            cx.propagate();
12713            return;
12714        }
12715
12716        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12717
12718        let text_layout_details = &self.text_layout_details(window);
12719        let selection_count = self.selections.count();
12720        let first_selection = self.selections.first_anchor();
12721
12722        self.change_selections(Default::default(), window, cx, |s| {
12723            s.move_with(|map, selection| {
12724                if !selection.is_empty() {
12725                    selection.goal = SelectionGoal::None;
12726                }
12727                let (cursor, goal) = movement::up(
12728                    map,
12729                    selection.start,
12730                    selection.goal,
12731                    false,
12732                    text_layout_details,
12733                );
12734                selection.collapse_to(cursor, goal);
12735            });
12736        });
12737
12738        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12739        {
12740            cx.propagate();
12741        }
12742    }
12743
12744    pub fn move_up_by_lines(
12745        &mut self,
12746        action: &MoveUpByLines,
12747        window: &mut Window,
12748        cx: &mut Context<Self>,
12749    ) {
12750        if self.take_rename(true, window, cx).is_some() {
12751            return;
12752        }
12753
12754        if self.mode.is_single_line() {
12755            cx.propagate();
12756            return;
12757        }
12758
12759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12760
12761        let text_layout_details = &self.text_layout_details(window);
12762
12763        self.change_selections(Default::default(), window, cx, |s| {
12764            s.move_with(|map, selection| {
12765                if !selection.is_empty() {
12766                    selection.goal = SelectionGoal::None;
12767                }
12768                let (cursor, goal) = movement::up_by_rows(
12769                    map,
12770                    selection.start,
12771                    action.lines,
12772                    selection.goal,
12773                    false,
12774                    text_layout_details,
12775                );
12776                selection.collapse_to(cursor, goal);
12777            });
12778        })
12779    }
12780
12781    pub fn move_down_by_lines(
12782        &mut self,
12783        action: &MoveDownByLines,
12784        window: &mut Window,
12785        cx: &mut Context<Self>,
12786    ) {
12787        if self.take_rename(true, window, cx).is_some() {
12788            return;
12789        }
12790
12791        if self.mode.is_single_line() {
12792            cx.propagate();
12793            return;
12794        }
12795
12796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12797
12798        let text_layout_details = &self.text_layout_details(window);
12799
12800        self.change_selections(Default::default(), window, cx, |s| {
12801            s.move_with(|map, selection| {
12802                if !selection.is_empty() {
12803                    selection.goal = SelectionGoal::None;
12804                }
12805                let (cursor, goal) = movement::down_by_rows(
12806                    map,
12807                    selection.start,
12808                    action.lines,
12809                    selection.goal,
12810                    false,
12811                    text_layout_details,
12812                );
12813                selection.collapse_to(cursor, goal);
12814            });
12815        })
12816    }
12817
12818    pub fn select_down_by_lines(
12819        &mut self,
12820        action: &SelectDownByLines,
12821        window: &mut Window,
12822        cx: &mut Context<Self>,
12823    ) {
12824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12825        let text_layout_details = &self.text_layout_details(window);
12826        self.change_selections(Default::default(), window, cx, |s| {
12827            s.move_heads_with(|map, head, goal| {
12828                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12829            })
12830        })
12831    }
12832
12833    pub fn select_up_by_lines(
12834        &mut self,
12835        action: &SelectUpByLines,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12840        let text_layout_details = &self.text_layout_details(window);
12841        self.change_selections(Default::default(), window, cx, |s| {
12842            s.move_heads_with(|map, head, goal| {
12843                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12844            })
12845        })
12846    }
12847
12848    pub fn select_page_up(
12849        &mut self,
12850        _: &SelectPageUp,
12851        window: &mut Window,
12852        cx: &mut Context<Self>,
12853    ) {
12854        let Some(row_count) = self.visible_row_count() else {
12855            return;
12856        };
12857
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12859
12860        let text_layout_details = &self.text_layout_details(window);
12861
12862        self.change_selections(Default::default(), window, cx, |s| {
12863            s.move_heads_with(|map, head, goal| {
12864                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12865            })
12866        })
12867    }
12868
12869    pub fn move_page_up(
12870        &mut self,
12871        action: &MovePageUp,
12872        window: &mut Window,
12873        cx: &mut Context<Self>,
12874    ) {
12875        if self.take_rename(true, window, cx).is_some() {
12876            return;
12877        }
12878
12879        if self
12880            .context_menu
12881            .borrow_mut()
12882            .as_mut()
12883            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12884            .unwrap_or(false)
12885        {
12886            return;
12887        }
12888
12889        if matches!(self.mode, EditorMode::SingleLine) {
12890            cx.propagate();
12891            return;
12892        }
12893
12894        let Some(row_count) = self.visible_row_count() else {
12895            return;
12896        };
12897
12898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12899
12900        let effects = if action.center_cursor {
12901            SelectionEffects::scroll(Autoscroll::center())
12902        } else {
12903            SelectionEffects::default()
12904        };
12905
12906        let text_layout_details = &self.text_layout_details(window);
12907
12908        self.change_selections(effects, window, cx, |s| {
12909            s.move_with(|map, selection| {
12910                if !selection.is_empty() {
12911                    selection.goal = SelectionGoal::None;
12912                }
12913                let (cursor, goal) = movement::up_by_rows(
12914                    map,
12915                    selection.end,
12916                    row_count,
12917                    selection.goal,
12918                    false,
12919                    text_layout_details,
12920                );
12921                selection.collapse_to(cursor, goal);
12922            });
12923        });
12924    }
12925
12926    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12928        let text_layout_details = &self.text_layout_details(window);
12929        self.change_selections(Default::default(), window, cx, |s| {
12930            s.move_heads_with(|map, head, goal| {
12931                movement::up(map, head, goal, false, text_layout_details)
12932            })
12933        })
12934    }
12935
12936    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12937        self.take_rename(true, window, cx);
12938
12939        if self.mode.is_single_line() {
12940            cx.propagate();
12941            return;
12942        }
12943
12944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12945
12946        let text_layout_details = &self.text_layout_details(window);
12947        let selection_count = self.selections.count();
12948        let first_selection = self.selections.first_anchor();
12949
12950        self.change_selections(Default::default(), window, cx, |s| {
12951            s.move_with(|map, selection| {
12952                if !selection.is_empty() {
12953                    selection.goal = SelectionGoal::None;
12954                }
12955                let (cursor, goal) = movement::down(
12956                    map,
12957                    selection.end,
12958                    selection.goal,
12959                    false,
12960                    text_layout_details,
12961                );
12962                selection.collapse_to(cursor, goal);
12963            });
12964        });
12965
12966        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12967        {
12968            cx.propagate();
12969        }
12970    }
12971
12972    pub fn select_page_down(
12973        &mut self,
12974        _: &SelectPageDown,
12975        window: &mut Window,
12976        cx: &mut Context<Self>,
12977    ) {
12978        let Some(row_count) = self.visible_row_count() else {
12979            return;
12980        };
12981
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12983
12984        let text_layout_details = &self.text_layout_details(window);
12985
12986        self.change_selections(Default::default(), window, cx, |s| {
12987            s.move_heads_with(|map, head, goal| {
12988                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12989            })
12990        })
12991    }
12992
12993    pub fn move_page_down(
12994        &mut self,
12995        action: &MovePageDown,
12996        window: &mut Window,
12997        cx: &mut Context<Self>,
12998    ) {
12999        if self.take_rename(true, window, cx).is_some() {
13000            return;
13001        }
13002
13003        if self
13004            .context_menu
13005            .borrow_mut()
13006            .as_mut()
13007            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13008            .unwrap_or(false)
13009        {
13010            return;
13011        }
13012
13013        if matches!(self.mode, EditorMode::SingleLine) {
13014            cx.propagate();
13015            return;
13016        }
13017
13018        let Some(row_count) = self.visible_row_count() else {
13019            return;
13020        };
13021
13022        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13023
13024        let effects = if action.center_cursor {
13025            SelectionEffects::scroll(Autoscroll::center())
13026        } else {
13027            SelectionEffects::default()
13028        };
13029
13030        let text_layout_details = &self.text_layout_details(window);
13031        self.change_selections(effects, window, cx, |s| {
13032            s.move_with(|map, selection| {
13033                if !selection.is_empty() {
13034                    selection.goal = SelectionGoal::None;
13035                }
13036                let (cursor, goal) = movement::down_by_rows(
13037                    map,
13038                    selection.end,
13039                    row_count,
13040                    selection.goal,
13041                    false,
13042                    text_layout_details,
13043                );
13044                selection.collapse_to(cursor, goal);
13045            });
13046        });
13047    }
13048
13049    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13051        let text_layout_details = &self.text_layout_details(window);
13052        self.change_selections(Default::default(), window, cx, |s| {
13053            s.move_heads_with(|map, head, goal| {
13054                movement::down(map, head, goal, false, text_layout_details)
13055            })
13056        });
13057    }
13058
13059    pub fn context_menu_first(
13060        &mut self,
13061        _: &ContextMenuFirst,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13066            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13067        }
13068    }
13069
13070    pub fn context_menu_prev(
13071        &mut self,
13072        _: &ContextMenuPrevious,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13077            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13078        }
13079    }
13080
13081    pub fn context_menu_next(
13082        &mut self,
13083        _: &ContextMenuNext,
13084        window: &mut Window,
13085        cx: &mut Context<Self>,
13086    ) {
13087        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13088            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13089        }
13090    }
13091
13092    pub fn context_menu_last(
13093        &mut self,
13094        _: &ContextMenuLast,
13095        window: &mut Window,
13096        cx: &mut Context<Self>,
13097    ) {
13098        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13099            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13100        }
13101    }
13102
13103    pub fn signature_help_prev(
13104        &mut self,
13105        _: &SignatureHelpPrevious,
13106        _: &mut Window,
13107        cx: &mut Context<Self>,
13108    ) {
13109        if let Some(popover) = self.signature_help_state.popover_mut() {
13110            if popover.current_signature == 0 {
13111                popover.current_signature = popover.signatures.len() - 1;
13112            } else {
13113                popover.current_signature -= 1;
13114            }
13115            cx.notify();
13116        }
13117    }
13118
13119    pub fn signature_help_next(
13120        &mut self,
13121        _: &SignatureHelpNext,
13122        _: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        if let Some(popover) = self.signature_help_state.popover_mut() {
13126            if popover.current_signature + 1 == popover.signatures.len() {
13127                popover.current_signature = 0;
13128            } else {
13129                popover.current_signature += 1;
13130            }
13131            cx.notify();
13132        }
13133    }
13134
13135    pub fn move_to_previous_word_start(
13136        &mut self,
13137        _: &MoveToPreviousWordStart,
13138        window: &mut Window,
13139        cx: &mut Context<Self>,
13140    ) {
13141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13142        self.change_selections(Default::default(), window, cx, |s| {
13143            s.move_cursors_with(|map, head, _| {
13144                (
13145                    movement::previous_word_start(map, head),
13146                    SelectionGoal::None,
13147                )
13148            });
13149        })
13150    }
13151
13152    pub fn move_to_previous_subword_start(
13153        &mut self,
13154        _: &MoveToPreviousSubwordStart,
13155        window: &mut Window,
13156        cx: &mut Context<Self>,
13157    ) {
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13159        self.change_selections(Default::default(), window, cx, |s| {
13160            s.move_cursors_with(|map, head, _| {
13161                (
13162                    movement::previous_subword_start(map, head),
13163                    SelectionGoal::None,
13164                )
13165            });
13166        })
13167    }
13168
13169    pub fn select_to_previous_word_start(
13170        &mut self,
13171        _: &SelectToPreviousWordStart,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13176        self.change_selections(Default::default(), window, cx, |s| {
13177            s.move_heads_with(|map, head, _| {
13178                (
13179                    movement::previous_word_start(map, head),
13180                    SelectionGoal::None,
13181                )
13182            });
13183        })
13184    }
13185
13186    pub fn select_to_previous_subword_start(
13187        &mut self,
13188        _: &SelectToPreviousSubwordStart,
13189        window: &mut Window,
13190        cx: &mut Context<Self>,
13191    ) {
13192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13193        self.change_selections(Default::default(), window, cx, |s| {
13194            s.move_heads_with(|map, head, _| {
13195                (
13196                    movement::previous_subword_start(map, head),
13197                    SelectionGoal::None,
13198                )
13199            });
13200        })
13201    }
13202
13203    pub fn delete_to_previous_word_start(
13204        &mut self,
13205        action: &DeleteToPreviousWordStart,
13206        window: &mut Window,
13207        cx: &mut Context<Self>,
13208    ) {
13209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13210        self.transact(window, cx, |this, window, cx| {
13211            this.select_autoclose_pair(window, cx);
13212            this.change_selections(Default::default(), window, cx, |s| {
13213                s.move_with(|map, selection| {
13214                    if selection.is_empty() {
13215                        let mut cursor = if action.ignore_newlines {
13216                            movement::previous_word_start(map, selection.head())
13217                        } else {
13218                            movement::previous_word_start_or_newline(map, selection.head())
13219                        };
13220                        cursor = movement::adjust_greedy_deletion(
13221                            map,
13222                            selection.head(),
13223                            cursor,
13224                            action.ignore_brackets,
13225                        );
13226                        selection.set_head(cursor, SelectionGoal::None);
13227                    }
13228                });
13229            });
13230            this.insert("", window, cx);
13231        });
13232    }
13233
13234    pub fn delete_to_previous_subword_start(
13235        &mut self,
13236        _: &DeleteToPreviousSubwordStart,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13241        self.transact(window, cx, |this, window, cx| {
13242            this.select_autoclose_pair(window, cx);
13243            this.change_selections(Default::default(), window, cx, |s| {
13244                s.move_with(|map, selection| {
13245                    if selection.is_empty() {
13246                        let mut cursor = movement::previous_subword_start(map, selection.head());
13247                        cursor =
13248                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13249                        selection.set_head(cursor, SelectionGoal::None);
13250                    }
13251                });
13252            });
13253            this.insert("", window, cx);
13254        });
13255    }
13256
13257    pub fn move_to_next_word_end(
13258        &mut self,
13259        _: &MoveToNextWordEnd,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264        self.change_selections(Default::default(), window, cx, |s| {
13265            s.move_cursors_with(|map, head, _| {
13266                (movement::next_word_end(map, head), SelectionGoal::None)
13267            });
13268        })
13269    }
13270
13271    pub fn move_to_next_subword_end(
13272        &mut self,
13273        _: &MoveToNextSubwordEnd,
13274        window: &mut Window,
13275        cx: &mut Context<Self>,
13276    ) {
13277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13278        self.change_selections(Default::default(), window, cx, |s| {
13279            s.move_cursors_with(|map, head, _| {
13280                (movement::next_subword_end(map, head), SelectionGoal::None)
13281            });
13282        })
13283    }
13284
13285    pub fn select_to_next_word_end(
13286        &mut self,
13287        _: &SelectToNextWordEnd,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13292        self.change_selections(Default::default(), window, cx, |s| {
13293            s.move_heads_with(|map, head, _| {
13294                (movement::next_word_end(map, head), SelectionGoal::None)
13295            });
13296        })
13297    }
13298
13299    pub fn select_to_next_subword_end(
13300        &mut self,
13301        _: &SelectToNextSubwordEnd,
13302        window: &mut Window,
13303        cx: &mut Context<Self>,
13304    ) {
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13306        self.change_selections(Default::default(), window, cx, |s| {
13307            s.move_heads_with(|map, head, _| {
13308                (movement::next_subword_end(map, head), SelectionGoal::None)
13309            });
13310        })
13311    }
13312
13313    pub fn delete_to_next_word_end(
13314        &mut self,
13315        action: &DeleteToNextWordEnd,
13316        window: &mut Window,
13317        cx: &mut Context<Self>,
13318    ) {
13319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13320        self.transact(window, cx, |this, window, cx| {
13321            this.change_selections(Default::default(), window, cx, |s| {
13322                s.move_with(|map, selection| {
13323                    if selection.is_empty() {
13324                        let mut cursor = if action.ignore_newlines {
13325                            movement::next_word_end(map, selection.head())
13326                        } else {
13327                            movement::next_word_end_or_newline(map, selection.head())
13328                        };
13329                        cursor = movement::adjust_greedy_deletion(
13330                            map,
13331                            selection.head(),
13332                            cursor,
13333                            action.ignore_brackets,
13334                        );
13335                        selection.set_head(cursor, SelectionGoal::None);
13336                    }
13337                });
13338            });
13339            this.insert("", window, cx);
13340        });
13341    }
13342
13343    pub fn delete_to_next_subword_end(
13344        &mut self,
13345        _: &DeleteToNextSubwordEnd,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13350        self.transact(window, cx, |this, window, cx| {
13351            this.change_selections(Default::default(), window, cx, |s| {
13352                s.move_with(|map, selection| {
13353                    if selection.is_empty() {
13354                        let mut cursor = movement::next_subword_end(map, selection.head());
13355                        cursor =
13356                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13357                        selection.set_head(cursor, SelectionGoal::None);
13358                    }
13359                });
13360            });
13361            this.insert("", window, cx);
13362        });
13363    }
13364
13365    pub fn move_to_beginning_of_line(
13366        &mut self,
13367        action: &MoveToBeginningOfLine,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13372        self.change_selections(Default::default(), window, cx, |s| {
13373            s.move_cursors_with(|map, head, _| {
13374                (
13375                    movement::indented_line_beginning(
13376                        map,
13377                        head,
13378                        action.stop_at_soft_wraps,
13379                        action.stop_at_indent,
13380                    ),
13381                    SelectionGoal::None,
13382                )
13383            });
13384        })
13385    }
13386
13387    pub fn select_to_beginning_of_line(
13388        &mut self,
13389        action: &SelectToBeginningOfLine,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13394        self.change_selections(Default::default(), window, cx, |s| {
13395            s.move_heads_with(|map, head, _| {
13396                (
13397                    movement::indented_line_beginning(
13398                        map,
13399                        head,
13400                        action.stop_at_soft_wraps,
13401                        action.stop_at_indent,
13402                    ),
13403                    SelectionGoal::None,
13404                )
13405            });
13406        });
13407    }
13408
13409    pub fn delete_to_beginning_of_line(
13410        &mut self,
13411        action: &DeleteToBeginningOfLine,
13412        window: &mut Window,
13413        cx: &mut Context<Self>,
13414    ) {
13415        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13416        self.transact(window, cx, |this, window, cx| {
13417            this.change_selections(Default::default(), window, cx, |s| {
13418                s.move_with(|_, selection| {
13419                    selection.reversed = true;
13420                });
13421            });
13422
13423            this.select_to_beginning_of_line(
13424                &SelectToBeginningOfLine {
13425                    stop_at_soft_wraps: false,
13426                    stop_at_indent: action.stop_at_indent,
13427                },
13428                window,
13429                cx,
13430            );
13431            this.backspace(&Backspace, window, cx);
13432        });
13433    }
13434
13435    pub fn move_to_end_of_line(
13436        &mut self,
13437        action: &MoveToEndOfLine,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13442        self.change_selections(Default::default(), window, cx, |s| {
13443            s.move_cursors_with(|map, head, _| {
13444                (
13445                    movement::line_end(map, head, action.stop_at_soft_wraps),
13446                    SelectionGoal::None,
13447                )
13448            });
13449        })
13450    }
13451
13452    pub fn select_to_end_of_line(
13453        &mut self,
13454        action: &SelectToEndOfLine,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_heads_with(|map, head, _| {
13461                (
13462                    movement::line_end(map, head, action.stop_at_soft_wraps),
13463                    SelectionGoal::None,
13464                )
13465            });
13466        })
13467    }
13468
13469    pub fn delete_to_end_of_line(
13470        &mut self,
13471        _: &DeleteToEndOfLine,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) {
13475        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13476        self.transact(window, cx, |this, window, cx| {
13477            this.select_to_end_of_line(
13478                &SelectToEndOfLine {
13479                    stop_at_soft_wraps: false,
13480                },
13481                window,
13482                cx,
13483            );
13484            this.delete(&Delete, window, cx);
13485        });
13486    }
13487
13488    pub fn cut_to_end_of_line(
13489        &mut self,
13490        action: &CutToEndOfLine,
13491        window: &mut Window,
13492        cx: &mut Context<Self>,
13493    ) {
13494        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13495        self.transact(window, cx, |this, window, cx| {
13496            this.select_to_end_of_line(
13497                &SelectToEndOfLine {
13498                    stop_at_soft_wraps: false,
13499                },
13500                window,
13501                cx,
13502            );
13503            if !action.stop_at_newlines {
13504                this.change_selections(Default::default(), window, cx, |s| {
13505                    s.move_with(|_, sel| {
13506                        if sel.is_empty() {
13507                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13508                        }
13509                    });
13510                });
13511            }
13512            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13513            let item = this.cut_common(false, window, cx);
13514            cx.write_to_clipboard(item);
13515        });
13516    }
13517
13518    pub fn move_to_start_of_paragraph(
13519        &mut self,
13520        _: &MoveToStartOfParagraph,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        if matches!(self.mode, EditorMode::SingleLine) {
13525            cx.propagate();
13526            return;
13527        }
13528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13529        self.change_selections(Default::default(), window, cx, |s| {
13530            s.move_with(|map, selection| {
13531                selection.collapse_to(
13532                    movement::start_of_paragraph(map, selection.head(), 1),
13533                    SelectionGoal::None,
13534                )
13535            });
13536        })
13537    }
13538
13539    pub fn move_to_end_of_paragraph(
13540        &mut self,
13541        _: &MoveToEndOfParagraph,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) {
13545        if matches!(self.mode, EditorMode::SingleLine) {
13546            cx.propagate();
13547            return;
13548        }
13549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13550        self.change_selections(Default::default(), window, cx, |s| {
13551            s.move_with(|map, selection| {
13552                selection.collapse_to(
13553                    movement::end_of_paragraph(map, selection.head(), 1),
13554                    SelectionGoal::None,
13555                )
13556            });
13557        })
13558    }
13559
13560    pub fn select_to_start_of_paragraph(
13561        &mut self,
13562        _: &SelectToStartOfParagraph,
13563        window: &mut Window,
13564        cx: &mut Context<Self>,
13565    ) {
13566        if matches!(self.mode, EditorMode::SingleLine) {
13567            cx.propagate();
13568            return;
13569        }
13570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13571        self.change_selections(Default::default(), window, cx, |s| {
13572            s.move_heads_with(|map, head, _| {
13573                (
13574                    movement::start_of_paragraph(map, head, 1),
13575                    SelectionGoal::None,
13576                )
13577            });
13578        })
13579    }
13580
13581    pub fn select_to_end_of_paragraph(
13582        &mut self,
13583        _: &SelectToEndOfParagraph,
13584        window: &mut Window,
13585        cx: &mut Context<Self>,
13586    ) {
13587        if matches!(self.mode, EditorMode::SingleLine) {
13588            cx.propagate();
13589            return;
13590        }
13591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13592        self.change_selections(Default::default(), window, cx, |s| {
13593            s.move_heads_with(|map, head, _| {
13594                (
13595                    movement::end_of_paragraph(map, head, 1),
13596                    SelectionGoal::None,
13597                )
13598            });
13599        })
13600    }
13601
13602    pub fn move_to_start_of_excerpt(
13603        &mut self,
13604        _: &MoveToStartOfExcerpt,
13605        window: &mut Window,
13606        cx: &mut Context<Self>,
13607    ) {
13608        if matches!(self.mode, EditorMode::SingleLine) {
13609            cx.propagate();
13610            return;
13611        }
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13613        self.change_selections(Default::default(), window, cx, |s| {
13614            s.move_with(|map, selection| {
13615                selection.collapse_to(
13616                    movement::start_of_excerpt(
13617                        map,
13618                        selection.head(),
13619                        workspace::searchable::Direction::Prev,
13620                    ),
13621                    SelectionGoal::None,
13622                )
13623            });
13624        })
13625    }
13626
13627    pub fn move_to_start_of_next_excerpt(
13628        &mut self,
13629        _: &MoveToStartOfNextExcerpt,
13630        window: &mut Window,
13631        cx: &mut Context<Self>,
13632    ) {
13633        if matches!(self.mode, EditorMode::SingleLine) {
13634            cx.propagate();
13635            return;
13636        }
13637
13638        self.change_selections(Default::default(), window, cx, |s| {
13639            s.move_with(|map, selection| {
13640                selection.collapse_to(
13641                    movement::start_of_excerpt(
13642                        map,
13643                        selection.head(),
13644                        workspace::searchable::Direction::Next,
13645                    ),
13646                    SelectionGoal::None,
13647                )
13648            });
13649        })
13650    }
13651
13652    pub fn move_to_end_of_excerpt(
13653        &mut self,
13654        _: &MoveToEndOfExcerpt,
13655        window: &mut Window,
13656        cx: &mut Context<Self>,
13657    ) {
13658        if matches!(self.mode, EditorMode::SingleLine) {
13659            cx.propagate();
13660            return;
13661        }
13662        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13663        self.change_selections(Default::default(), window, cx, |s| {
13664            s.move_with(|map, selection| {
13665                selection.collapse_to(
13666                    movement::end_of_excerpt(
13667                        map,
13668                        selection.head(),
13669                        workspace::searchable::Direction::Next,
13670                    ),
13671                    SelectionGoal::None,
13672                )
13673            });
13674        })
13675    }
13676
13677    pub fn move_to_end_of_previous_excerpt(
13678        &mut self,
13679        _: &MoveToEndOfPreviousExcerpt,
13680        window: &mut Window,
13681        cx: &mut Context<Self>,
13682    ) {
13683        if matches!(self.mode, EditorMode::SingleLine) {
13684            cx.propagate();
13685            return;
13686        }
13687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13688        self.change_selections(Default::default(), window, cx, |s| {
13689            s.move_with(|map, selection| {
13690                selection.collapse_to(
13691                    movement::end_of_excerpt(
13692                        map,
13693                        selection.head(),
13694                        workspace::searchable::Direction::Prev,
13695                    ),
13696                    SelectionGoal::None,
13697                )
13698            });
13699        })
13700    }
13701
13702    pub fn select_to_start_of_excerpt(
13703        &mut self,
13704        _: &SelectToStartOfExcerpt,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        if matches!(self.mode, EditorMode::SingleLine) {
13709            cx.propagate();
13710            return;
13711        }
13712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13713        self.change_selections(Default::default(), window, cx, |s| {
13714            s.move_heads_with(|map, head, _| {
13715                (
13716                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13717                    SelectionGoal::None,
13718                )
13719            });
13720        })
13721    }
13722
13723    pub fn select_to_start_of_next_excerpt(
13724        &mut self,
13725        _: &SelectToStartOfNextExcerpt,
13726        window: &mut Window,
13727        cx: &mut Context<Self>,
13728    ) {
13729        if matches!(self.mode, EditorMode::SingleLine) {
13730            cx.propagate();
13731            return;
13732        }
13733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13734        self.change_selections(Default::default(), window, cx, |s| {
13735            s.move_heads_with(|map, head, _| {
13736                (
13737                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13738                    SelectionGoal::None,
13739                )
13740            });
13741        })
13742    }
13743
13744    pub fn select_to_end_of_excerpt(
13745        &mut self,
13746        _: &SelectToEndOfExcerpt,
13747        window: &mut Window,
13748        cx: &mut Context<Self>,
13749    ) {
13750        if matches!(self.mode, EditorMode::SingleLine) {
13751            cx.propagate();
13752            return;
13753        }
13754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13755        self.change_selections(Default::default(), window, cx, |s| {
13756            s.move_heads_with(|map, head, _| {
13757                (
13758                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13759                    SelectionGoal::None,
13760                )
13761            });
13762        })
13763    }
13764
13765    pub fn select_to_end_of_previous_excerpt(
13766        &mut self,
13767        _: &SelectToEndOfPreviousExcerpt,
13768        window: &mut Window,
13769        cx: &mut Context<Self>,
13770    ) {
13771        if matches!(self.mode, EditorMode::SingleLine) {
13772            cx.propagate();
13773            return;
13774        }
13775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13776        self.change_selections(Default::default(), window, cx, |s| {
13777            s.move_heads_with(|map, head, _| {
13778                (
13779                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13780                    SelectionGoal::None,
13781                )
13782            });
13783        })
13784    }
13785
13786    pub fn move_to_beginning(
13787        &mut self,
13788        _: &MoveToBeginning,
13789        window: &mut Window,
13790        cx: &mut Context<Self>,
13791    ) {
13792        if matches!(self.mode, EditorMode::SingleLine) {
13793            cx.propagate();
13794            return;
13795        }
13796        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13797        self.change_selections(Default::default(), window, cx, |s| {
13798            s.select_ranges(vec![0..0]);
13799        });
13800    }
13801
13802    pub fn select_to_beginning(
13803        &mut self,
13804        _: &SelectToBeginning,
13805        window: &mut Window,
13806        cx: &mut Context<Self>,
13807    ) {
13808        let mut selection = self.selections.last::<Point>(cx);
13809        selection.set_head(Point::zero(), SelectionGoal::None);
13810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13811        self.change_selections(Default::default(), window, cx, |s| {
13812            s.select(vec![selection]);
13813        });
13814    }
13815
13816    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13817        if matches!(self.mode, EditorMode::SingleLine) {
13818            cx.propagate();
13819            return;
13820        }
13821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13822        let cursor = self.buffer.read(cx).read(cx).len();
13823        self.change_selections(Default::default(), window, cx, |s| {
13824            s.select_ranges(vec![cursor..cursor])
13825        });
13826    }
13827
13828    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13829        self.nav_history = nav_history;
13830    }
13831
13832    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13833        self.nav_history.as_ref()
13834    }
13835
13836    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13837        self.push_to_nav_history(
13838            self.selections.newest_anchor().head(),
13839            None,
13840            false,
13841            true,
13842            cx,
13843        );
13844    }
13845
13846    fn push_to_nav_history(
13847        &mut self,
13848        cursor_anchor: Anchor,
13849        new_position: Option<Point>,
13850        is_deactivate: bool,
13851        always: bool,
13852        cx: &mut Context<Self>,
13853    ) {
13854        if let Some(nav_history) = self.nav_history.as_mut() {
13855            let buffer = self.buffer.read(cx).read(cx);
13856            let cursor_position = cursor_anchor.to_point(&buffer);
13857            let scroll_state = self.scroll_manager.anchor();
13858            let scroll_top_row = scroll_state.top_row(&buffer);
13859            drop(buffer);
13860
13861            if let Some(new_position) = new_position {
13862                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13863                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13864                    return;
13865                }
13866            }
13867
13868            nav_history.push(
13869                Some(NavigationData {
13870                    cursor_anchor,
13871                    cursor_position,
13872                    scroll_anchor: scroll_state,
13873                    scroll_top_row,
13874                }),
13875                cx,
13876            );
13877            cx.emit(EditorEvent::PushedToNavHistory {
13878                anchor: cursor_anchor,
13879                is_deactivate,
13880            })
13881        }
13882    }
13883
13884    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13886        let buffer = self.buffer.read(cx).snapshot(cx);
13887        let mut selection = self.selections.first::<usize>(cx);
13888        selection.set_head(buffer.len(), SelectionGoal::None);
13889        self.change_selections(Default::default(), window, cx, |s| {
13890            s.select(vec![selection]);
13891        });
13892    }
13893
13894    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13896        let end = self.buffer.read(cx).read(cx).len();
13897        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13898            s.select_ranges(vec![0..end]);
13899        });
13900    }
13901
13902    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13904        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13905        let mut selections = self.selections.all::<Point>(cx);
13906        let max_point = display_map.buffer_snapshot.max_point();
13907        for selection in &mut selections {
13908            let rows = selection.spanned_rows(true, &display_map);
13909            selection.start = Point::new(rows.start.0, 0);
13910            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13911            selection.reversed = false;
13912        }
13913        self.change_selections(Default::default(), window, cx, |s| {
13914            s.select(selections);
13915        });
13916    }
13917
13918    pub fn split_selection_into_lines(
13919        &mut self,
13920        action: &SplitSelectionIntoLines,
13921        window: &mut Window,
13922        cx: &mut Context<Self>,
13923    ) {
13924        let selections = self
13925            .selections
13926            .all::<Point>(cx)
13927            .into_iter()
13928            .map(|selection| selection.start..selection.end)
13929            .collect::<Vec<_>>();
13930        self.unfold_ranges(&selections, true, true, cx);
13931
13932        let mut new_selection_ranges = Vec::new();
13933        {
13934            let buffer = self.buffer.read(cx).read(cx);
13935            for selection in selections {
13936                for row in selection.start.row..selection.end.row {
13937                    let line_start = Point::new(row, 0);
13938                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13939
13940                    if action.keep_selections {
13941                        // Keep the selection range for each line
13942                        let selection_start = if row == selection.start.row {
13943                            selection.start
13944                        } else {
13945                            line_start
13946                        };
13947                        new_selection_ranges.push(selection_start..line_end);
13948                    } else {
13949                        // Collapse to cursor at end of line
13950                        new_selection_ranges.push(line_end..line_end);
13951                    }
13952                }
13953
13954                let is_multiline_selection = selection.start.row != selection.end.row;
13955                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13956                // so this action feels more ergonomic when paired with other selection operations
13957                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13958                if !should_skip_last {
13959                    if action.keep_selections {
13960                        if is_multiline_selection {
13961                            let line_start = Point::new(selection.end.row, 0);
13962                            new_selection_ranges.push(line_start..selection.end);
13963                        } else {
13964                            new_selection_ranges.push(selection.start..selection.end);
13965                        }
13966                    } else {
13967                        new_selection_ranges.push(selection.end..selection.end);
13968                    }
13969                }
13970            }
13971        }
13972        self.change_selections(Default::default(), window, cx, |s| {
13973            s.select_ranges(new_selection_ranges);
13974        });
13975    }
13976
13977    pub fn add_selection_above(
13978        &mut self,
13979        _: &AddSelectionAbove,
13980        window: &mut Window,
13981        cx: &mut Context<Self>,
13982    ) {
13983        self.add_selection(true, window, cx);
13984    }
13985
13986    pub fn add_selection_below(
13987        &mut self,
13988        _: &AddSelectionBelow,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        self.add_selection(false, window, cx);
13993    }
13994
13995    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997
13998        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13999        let all_selections = self.selections.all::<Point>(cx);
14000        let text_layout_details = self.text_layout_details(window);
14001
14002        let (mut columnar_selections, new_selections_to_columnarize) = {
14003            if let Some(state) = self.add_selections_state.as_ref() {
14004                let columnar_selection_ids: HashSet<_> = state
14005                    .groups
14006                    .iter()
14007                    .flat_map(|group| group.stack.iter())
14008                    .copied()
14009                    .collect();
14010
14011                all_selections
14012                    .into_iter()
14013                    .partition(|s| columnar_selection_ids.contains(&s.id))
14014            } else {
14015                (Vec::new(), all_selections)
14016            }
14017        };
14018
14019        let mut state = self
14020            .add_selections_state
14021            .take()
14022            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14023
14024        for selection in new_selections_to_columnarize {
14025            let range = selection.display_range(&display_map).sorted();
14026            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14027            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14028            let positions = start_x.min(end_x)..start_x.max(end_x);
14029            let mut stack = Vec::new();
14030            for row in range.start.row().0..=range.end.row().0 {
14031                if let Some(selection) = self.selections.build_columnar_selection(
14032                    &display_map,
14033                    DisplayRow(row),
14034                    &positions,
14035                    selection.reversed,
14036                    &text_layout_details,
14037                ) {
14038                    stack.push(selection.id);
14039                    columnar_selections.push(selection);
14040                }
14041            }
14042            if !stack.is_empty() {
14043                if above {
14044                    stack.reverse();
14045                }
14046                state.groups.push(AddSelectionsGroup { above, stack });
14047            }
14048        }
14049
14050        let mut final_selections = Vec::new();
14051        let end_row = if above {
14052            DisplayRow(0)
14053        } else {
14054            display_map.max_point().row()
14055        };
14056
14057        let mut last_added_item_per_group = HashMap::default();
14058        for group in state.groups.iter_mut() {
14059            if let Some(last_id) = group.stack.last() {
14060                last_added_item_per_group.insert(*last_id, group);
14061            }
14062        }
14063
14064        for selection in columnar_selections {
14065            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14066                if above == group.above {
14067                    let range = selection.display_range(&display_map).sorted();
14068                    debug_assert_eq!(range.start.row(), range.end.row());
14069                    let mut row = range.start.row();
14070                    let positions =
14071                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14072                            px(start)..px(end)
14073                        } else {
14074                            let start_x =
14075                                display_map.x_for_display_point(range.start, &text_layout_details);
14076                            let end_x =
14077                                display_map.x_for_display_point(range.end, &text_layout_details);
14078                            start_x.min(end_x)..start_x.max(end_x)
14079                        };
14080
14081                    let mut maybe_new_selection = None;
14082                    while row != end_row {
14083                        if above {
14084                            row.0 -= 1;
14085                        } else {
14086                            row.0 += 1;
14087                        }
14088                        if let Some(new_selection) = self.selections.build_columnar_selection(
14089                            &display_map,
14090                            row,
14091                            &positions,
14092                            selection.reversed,
14093                            &text_layout_details,
14094                        ) {
14095                            maybe_new_selection = Some(new_selection);
14096                            break;
14097                        }
14098                    }
14099
14100                    if let Some(new_selection) = maybe_new_selection {
14101                        group.stack.push(new_selection.id);
14102                        if above {
14103                            final_selections.push(new_selection);
14104                            final_selections.push(selection);
14105                        } else {
14106                            final_selections.push(selection);
14107                            final_selections.push(new_selection);
14108                        }
14109                    } else {
14110                        final_selections.push(selection);
14111                    }
14112                } else {
14113                    group.stack.pop();
14114                }
14115            } else {
14116                final_selections.push(selection);
14117            }
14118        }
14119
14120        self.change_selections(Default::default(), window, cx, |s| {
14121            s.select(final_selections);
14122        });
14123
14124        let final_selection_ids: HashSet<_> = self
14125            .selections
14126            .all::<Point>(cx)
14127            .iter()
14128            .map(|s| s.id)
14129            .collect();
14130        state.groups.retain_mut(|group| {
14131            // selections might get merged above so we remove invalid items from stacks
14132            group.stack.retain(|id| final_selection_ids.contains(id));
14133
14134            // single selection in stack can be treated as initial state
14135            group.stack.len() > 1
14136        });
14137
14138        if !state.groups.is_empty() {
14139            self.add_selections_state = Some(state);
14140        }
14141    }
14142
14143    fn select_match_ranges(
14144        &mut self,
14145        range: Range<usize>,
14146        reversed: bool,
14147        replace_newest: bool,
14148        auto_scroll: Option<Autoscroll>,
14149        window: &mut Window,
14150        cx: &mut Context<Editor>,
14151    ) {
14152        self.unfold_ranges(
14153            std::slice::from_ref(&range),
14154            false,
14155            auto_scroll.is_some(),
14156            cx,
14157        );
14158        let effects = if let Some(scroll) = auto_scroll {
14159            SelectionEffects::scroll(scroll)
14160        } else {
14161            SelectionEffects::no_scroll()
14162        };
14163        self.change_selections(effects, window, cx, |s| {
14164            if replace_newest {
14165                s.delete(s.newest_anchor().id);
14166            }
14167            if reversed {
14168                s.insert_range(range.end..range.start);
14169            } else {
14170                s.insert_range(range);
14171            }
14172        });
14173    }
14174
14175    pub fn select_next_match_internal(
14176        &mut self,
14177        display_map: &DisplaySnapshot,
14178        replace_newest: bool,
14179        autoscroll: Option<Autoscroll>,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) -> Result<()> {
14183        let buffer = &display_map.buffer_snapshot;
14184        let mut selections = self.selections.all::<usize>(cx);
14185        if let Some(mut select_next_state) = self.select_next_state.take() {
14186            let query = &select_next_state.query;
14187            if !select_next_state.done {
14188                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14189                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14190                let mut next_selected_range = None;
14191
14192                let bytes_after_last_selection =
14193                    buffer.bytes_in_range(last_selection.end..buffer.len());
14194                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14195                let query_matches = query
14196                    .stream_find_iter(bytes_after_last_selection)
14197                    .map(|result| (last_selection.end, result))
14198                    .chain(
14199                        query
14200                            .stream_find_iter(bytes_before_first_selection)
14201                            .map(|result| (0, result)),
14202                    );
14203
14204                for (start_offset, query_match) in query_matches {
14205                    let query_match = query_match.unwrap(); // can only fail due to I/O
14206                    let offset_range =
14207                        start_offset + query_match.start()..start_offset + query_match.end();
14208
14209                    if !select_next_state.wordwise
14210                        || (!buffer.is_inside_word(offset_range.start, false)
14211                            && !buffer.is_inside_word(offset_range.end, false))
14212                    {
14213                        // TODO: This is n^2, because we might check all the selections
14214                        if !selections
14215                            .iter()
14216                            .any(|selection| selection.range().overlaps(&offset_range))
14217                        {
14218                            next_selected_range = Some(offset_range);
14219                            break;
14220                        }
14221                    }
14222                }
14223
14224                if let Some(next_selected_range) = next_selected_range {
14225                    self.select_match_ranges(
14226                        next_selected_range,
14227                        last_selection.reversed,
14228                        replace_newest,
14229                        autoscroll,
14230                        window,
14231                        cx,
14232                    );
14233                } else {
14234                    select_next_state.done = true;
14235                }
14236            }
14237
14238            self.select_next_state = Some(select_next_state);
14239        } else {
14240            let mut only_carets = true;
14241            let mut same_text_selected = true;
14242            let mut selected_text = None;
14243
14244            let mut selections_iter = selections.iter().peekable();
14245            while let Some(selection) = selections_iter.next() {
14246                if selection.start != selection.end {
14247                    only_carets = false;
14248                }
14249
14250                if same_text_selected {
14251                    if selected_text.is_none() {
14252                        selected_text =
14253                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14254                    }
14255
14256                    if let Some(next_selection) = selections_iter.peek() {
14257                        if next_selection.range().len() == selection.range().len() {
14258                            let next_selected_text = buffer
14259                                .text_for_range(next_selection.range())
14260                                .collect::<String>();
14261                            if Some(next_selected_text) != selected_text {
14262                                same_text_selected = false;
14263                                selected_text = None;
14264                            }
14265                        } else {
14266                            same_text_selected = false;
14267                            selected_text = None;
14268                        }
14269                    }
14270                }
14271            }
14272
14273            if only_carets {
14274                for selection in &mut selections {
14275                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14276                    selection.start = word_range.start;
14277                    selection.end = word_range.end;
14278                    selection.goal = SelectionGoal::None;
14279                    selection.reversed = false;
14280                    self.select_match_ranges(
14281                        selection.start..selection.end,
14282                        selection.reversed,
14283                        replace_newest,
14284                        autoscroll,
14285                        window,
14286                        cx,
14287                    );
14288                }
14289
14290                if selections.len() == 1 {
14291                    let selection = selections
14292                        .last()
14293                        .expect("ensured that there's only one selection");
14294                    let query = buffer
14295                        .text_for_range(selection.start..selection.end)
14296                        .collect::<String>();
14297                    let is_empty = query.is_empty();
14298                    let select_state = SelectNextState {
14299                        query: AhoCorasick::new(&[query])?,
14300                        wordwise: true,
14301                        done: is_empty,
14302                    };
14303                    self.select_next_state = Some(select_state);
14304                } else {
14305                    self.select_next_state = None;
14306                }
14307            } else if let Some(selected_text) = selected_text {
14308                self.select_next_state = Some(SelectNextState {
14309                    query: AhoCorasick::new(&[selected_text])?,
14310                    wordwise: false,
14311                    done: false,
14312                });
14313                self.select_next_match_internal(
14314                    display_map,
14315                    replace_newest,
14316                    autoscroll,
14317                    window,
14318                    cx,
14319                )?;
14320            }
14321        }
14322        Ok(())
14323    }
14324
14325    pub fn select_all_matches(
14326        &mut self,
14327        _action: &SelectAllMatches,
14328        window: &mut Window,
14329        cx: &mut Context<Self>,
14330    ) -> Result<()> {
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14332
14333        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14334
14335        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14336        let Some(select_next_state) = self.select_next_state.as_mut() else {
14337            return Ok(());
14338        };
14339        if select_next_state.done {
14340            return Ok(());
14341        }
14342
14343        let mut new_selections = Vec::new();
14344
14345        let reversed = self.selections.oldest::<usize>(cx).reversed;
14346        let buffer = &display_map.buffer_snapshot;
14347        let query_matches = select_next_state
14348            .query
14349            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14350
14351        for query_match in query_matches.into_iter() {
14352            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14353            let offset_range = if reversed {
14354                query_match.end()..query_match.start()
14355            } else {
14356                query_match.start()..query_match.end()
14357            };
14358
14359            if !select_next_state.wordwise
14360                || (!buffer.is_inside_word(offset_range.start, false)
14361                    && !buffer.is_inside_word(offset_range.end, false))
14362            {
14363                new_selections.push(offset_range.start..offset_range.end);
14364            }
14365        }
14366
14367        select_next_state.done = true;
14368
14369        if new_selections.is_empty() {
14370            log::error!("bug: new_selections is empty in select_all_matches");
14371            return Ok(());
14372        }
14373
14374        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14375        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14376            selections.select_ranges(new_selections)
14377        });
14378
14379        Ok(())
14380    }
14381
14382    pub fn select_next(
14383        &mut self,
14384        action: &SelectNext,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) -> Result<()> {
14388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14390        self.select_next_match_internal(
14391            &display_map,
14392            action.replace_newest,
14393            Some(Autoscroll::newest()),
14394            window,
14395            cx,
14396        )?;
14397        Ok(())
14398    }
14399
14400    pub fn select_previous(
14401        &mut self,
14402        action: &SelectPrevious,
14403        window: &mut Window,
14404        cx: &mut Context<Self>,
14405    ) -> Result<()> {
14406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14407        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14408        let buffer = &display_map.buffer_snapshot;
14409        let mut selections = self.selections.all::<usize>(cx);
14410        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14411            let query = &select_prev_state.query;
14412            if !select_prev_state.done {
14413                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14414                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14415                let mut next_selected_range = None;
14416                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14417                let bytes_before_last_selection =
14418                    buffer.reversed_bytes_in_range(0..last_selection.start);
14419                let bytes_after_first_selection =
14420                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14421                let query_matches = query
14422                    .stream_find_iter(bytes_before_last_selection)
14423                    .map(|result| (last_selection.start, result))
14424                    .chain(
14425                        query
14426                            .stream_find_iter(bytes_after_first_selection)
14427                            .map(|result| (buffer.len(), result)),
14428                    );
14429                for (end_offset, query_match) in query_matches {
14430                    let query_match = query_match.unwrap(); // can only fail due to I/O
14431                    let offset_range =
14432                        end_offset - query_match.end()..end_offset - query_match.start();
14433
14434                    if !select_prev_state.wordwise
14435                        || (!buffer.is_inside_word(offset_range.start, false)
14436                            && !buffer.is_inside_word(offset_range.end, false))
14437                    {
14438                        next_selected_range = Some(offset_range);
14439                        break;
14440                    }
14441                }
14442
14443                if let Some(next_selected_range) = next_selected_range {
14444                    self.select_match_ranges(
14445                        next_selected_range,
14446                        last_selection.reversed,
14447                        action.replace_newest,
14448                        Some(Autoscroll::newest()),
14449                        window,
14450                        cx,
14451                    );
14452                } else {
14453                    select_prev_state.done = true;
14454                }
14455            }
14456
14457            self.select_prev_state = Some(select_prev_state);
14458        } else {
14459            let mut only_carets = true;
14460            let mut same_text_selected = true;
14461            let mut selected_text = None;
14462
14463            let mut selections_iter = selections.iter().peekable();
14464            while let Some(selection) = selections_iter.next() {
14465                if selection.start != selection.end {
14466                    only_carets = false;
14467                }
14468
14469                if same_text_selected {
14470                    if selected_text.is_none() {
14471                        selected_text =
14472                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14473                    }
14474
14475                    if let Some(next_selection) = selections_iter.peek() {
14476                        if next_selection.range().len() == selection.range().len() {
14477                            let next_selected_text = buffer
14478                                .text_for_range(next_selection.range())
14479                                .collect::<String>();
14480                            if Some(next_selected_text) != selected_text {
14481                                same_text_selected = false;
14482                                selected_text = None;
14483                            }
14484                        } else {
14485                            same_text_selected = false;
14486                            selected_text = None;
14487                        }
14488                    }
14489                }
14490            }
14491
14492            if only_carets {
14493                for selection in &mut selections {
14494                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14495                    selection.start = word_range.start;
14496                    selection.end = word_range.end;
14497                    selection.goal = SelectionGoal::None;
14498                    selection.reversed = false;
14499                    self.select_match_ranges(
14500                        selection.start..selection.end,
14501                        selection.reversed,
14502                        action.replace_newest,
14503                        Some(Autoscroll::newest()),
14504                        window,
14505                        cx,
14506                    );
14507                }
14508                if selections.len() == 1 {
14509                    let selection = selections
14510                        .last()
14511                        .expect("ensured that there's only one selection");
14512                    let query = buffer
14513                        .text_for_range(selection.start..selection.end)
14514                        .collect::<String>();
14515                    let is_empty = query.is_empty();
14516                    let select_state = SelectNextState {
14517                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14518                        wordwise: true,
14519                        done: is_empty,
14520                    };
14521                    self.select_prev_state = Some(select_state);
14522                } else {
14523                    self.select_prev_state = None;
14524                }
14525            } else if let Some(selected_text) = selected_text {
14526                self.select_prev_state = Some(SelectNextState {
14527                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14528                    wordwise: false,
14529                    done: false,
14530                });
14531                self.select_previous(action, window, cx)?;
14532            }
14533        }
14534        Ok(())
14535    }
14536
14537    pub fn find_next_match(
14538        &mut self,
14539        _: &FindNextMatch,
14540        window: &mut Window,
14541        cx: &mut Context<Self>,
14542    ) -> Result<()> {
14543        let selections = self.selections.disjoint_anchors_arc();
14544        match selections.first() {
14545            Some(first) if selections.len() >= 2 => {
14546                self.change_selections(Default::default(), window, cx, |s| {
14547                    s.select_ranges([first.range()]);
14548                });
14549            }
14550            _ => self.select_next(
14551                &SelectNext {
14552                    replace_newest: true,
14553                },
14554                window,
14555                cx,
14556            )?,
14557        }
14558        Ok(())
14559    }
14560
14561    pub fn find_previous_match(
14562        &mut self,
14563        _: &FindPreviousMatch,
14564        window: &mut Window,
14565        cx: &mut Context<Self>,
14566    ) -> Result<()> {
14567        let selections = self.selections.disjoint_anchors_arc();
14568        match selections.last() {
14569            Some(last) if selections.len() >= 2 => {
14570                self.change_selections(Default::default(), window, cx, |s| {
14571                    s.select_ranges([last.range()]);
14572                });
14573            }
14574            _ => self.select_previous(
14575                &SelectPrevious {
14576                    replace_newest: true,
14577                },
14578                window,
14579                cx,
14580            )?,
14581        }
14582        Ok(())
14583    }
14584
14585    pub fn toggle_comments(
14586        &mut self,
14587        action: &ToggleComments,
14588        window: &mut Window,
14589        cx: &mut Context<Self>,
14590    ) {
14591        if self.read_only(cx) {
14592            return;
14593        }
14594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14595        let text_layout_details = &self.text_layout_details(window);
14596        self.transact(window, cx, |this, window, cx| {
14597            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14598            let mut edits = Vec::new();
14599            let mut selection_edit_ranges = Vec::new();
14600            let mut last_toggled_row = None;
14601            let snapshot = this.buffer.read(cx).read(cx);
14602            let empty_str: Arc<str> = Arc::default();
14603            let mut suffixes_inserted = Vec::new();
14604            let ignore_indent = action.ignore_indent;
14605
14606            fn comment_prefix_range(
14607                snapshot: &MultiBufferSnapshot,
14608                row: MultiBufferRow,
14609                comment_prefix: &str,
14610                comment_prefix_whitespace: &str,
14611                ignore_indent: bool,
14612            ) -> Range<Point> {
14613                let indent_size = if ignore_indent {
14614                    0
14615                } else {
14616                    snapshot.indent_size_for_line(row).len
14617                };
14618
14619                let start = Point::new(row.0, indent_size);
14620
14621                let mut line_bytes = snapshot
14622                    .bytes_in_range(start..snapshot.max_point())
14623                    .flatten()
14624                    .copied();
14625
14626                // If this line currently begins with the line comment prefix, then record
14627                // the range containing the prefix.
14628                if line_bytes
14629                    .by_ref()
14630                    .take(comment_prefix.len())
14631                    .eq(comment_prefix.bytes())
14632                {
14633                    // Include any whitespace that matches the comment prefix.
14634                    let matching_whitespace_len = line_bytes
14635                        .zip(comment_prefix_whitespace.bytes())
14636                        .take_while(|(a, b)| a == b)
14637                        .count() as u32;
14638                    let end = Point::new(
14639                        start.row,
14640                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14641                    );
14642                    start..end
14643                } else {
14644                    start..start
14645                }
14646            }
14647
14648            fn comment_suffix_range(
14649                snapshot: &MultiBufferSnapshot,
14650                row: MultiBufferRow,
14651                comment_suffix: &str,
14652                comment_suffix_has_leading_space: bool,
14653            ) -> Range<Point> {
14654                let end = Point::new(row.0, snapshot.line_len(row));
14655                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14656
14657                let mut line_end_bytes = snapshot
14658                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14659                    .flatten()
14660                    .copied();
14661
14662                let leading_space_len = if suffix_start_column > 0
14663                    && line_end_bytes.next() == Some(b' ')
14664                    && comment_suffix_has_leading_space
14665                {
14666                    1
14667                } else {
14668                    0
14669                };
14670
14671                // If this line currently begins with the line comment prefix, then record
14672                // the range containing the prefix.
14673                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14674                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14675                    start..end
14676                } else {
14677                    end..end
14678                }
14679            }
14680
14681            // TODO: Handle selections that cross excerpts
14682            for selection in &mut selections {
14683                let start_column = snapshot
14684                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14685                    .len;
14686                let language = if let Some(language) =
14687                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14688                {
14689                    language
14690                } else {
14691                    continue;
14692                };
14693
14694                selection_edit_ranges.clear();
14695
14696                // If multiple selections contain a given row, avoid processing that
14697                // row more than once.
14698                let mut start_row = MultiBufferRow(selection.start.row);
14699                if last_toggled_row == Some(start_row) {
14700                    start_row = start_row.next_row();
14701                }
14702                let end_row =
14703                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14704                        MultiBufferRow(selection.end.row - 1)
14705                    } else {
14706                        MultiBufferRow(selection.end.row)
14707                    };
14708                last_toggled_row = Some(end_row);
14709
14710                if start_row > end_row {
14711                    continue;
14712                }
14713
14714                // If the language has line comments, toggle those.
14715                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14716
14717                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14718                if ignore_indent {
14719                    full_comment_prefixes = full_comment_prefixes
14720                        .into_iter()
14721                        .map(|s| Arc::from(s.trim_end()))
14722                        .collect();
14723                }
14724
14725                if !full_comment_prefixes.is_empty() {
14726                    let first_prefix = full_comment_prefixes
14727                        .first()
14728                        .expect("prefixes is non-empty");
14729                    let prefix_trimmed_lengths = full_comment_prefixes
14730                        .iter()
14731                        .map(|p| p.trim_end_matches(' ').len())
14732                        .collect::<SmallVec<[usize; 4]>>();
14733
14734                    let mut all_selection_lines_are_comments = true;
14735
14736                    for row in start_row.0..=end_row.0 {
14737                        let row = MultiBufferRow(row);
14738                        if start_row < end_row && snapshot.is_line_blank(row) {
14739                            continue;
14740                        }
14741
14742                        let prefix_range = full_comment_prefixes
14743                            .iter()
14744                            .zip(prefix_trimmed_lengths.iter().copied())
14745                            .map(|(prefix, trimmed_prefix_len)| {
14746                                comment_prefix_range(
14747                                    snapshot.deref(),
14748                                    row,
14749                                    &prefix[..trimmed_prefix_len],
14750                                    &prefix[trimmed_prefix_len..],
14751                                    ignore_indent,
14752                                )
14753                            })
14754                            .max_by_key(|range| range.end.column - range.start.column)
14755                            .expect("prefixes is non-empty");
14756
14757                        if prefix_range.is_empty() {
14758                            all_selection_lines_are_comments = false;
14759                        }
14760
14761                        selection_edit_ranges.push(prefix_range);
14762                    }
14763
14764                    if all_selection_lines_are_comments {
14765                        edits.extend(
14766                            selection_edit_ranges
14767                                .iter()
14768                                .cloned()
14769                                .map(|range| (range, empty_str.clone())),
14770                        );
14771                    } else {
14772                        let min_column = selection_edit_ranges
14773                            .iter()
14774                            .map(|range| range.start.column)
14775                            .min()
14776                            .unwrap_or(0);
14777                        edits.extend(selection_edit_ranges.iter().map(|range| {
14778                            let position = Point::new(range.start.row, min_column);
14779                            (position..position, first_prefix.clone())
14780                        }));
14781                    }
14782                } else if let Some(BlockCommentConfig {
14783                    start: full_comment_prefix,
14784                    end: comment_suffix,
14785                    ..
14786                }) = language.block_comment()
14787                {
14788                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14789                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14790                    let prefix_range = comment_prefix_range(
14791                        snapshot.deref(),
14792                        start_row,
14793                        comment_prefix,
14794                        comment_prefix_whitespace,
14795                        ignore_indent,
14796                    );
14797                    let suffix_range = comment_suffix_range(
14798                        snapshot.deref(),
14799                        end_row,
14800                        comment_suffix.trim_start_matches(' '),
14801                        comment_suffix.starts_with(' '),
14802                    );
14803
14804                    if prefix_range.is_empty() || suffix_range.is_empty() {
14805                        edits.push((
14806                            prefix_range.start..prefix_range.start,
14807                            full_comment_prefix.clone(),
14808                        ));
14809                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14810                        suffixes_inserted.push((end_row, comment_suffix.len()));
14811                    } else {
14812                        edits.push((prefix_range, empty_str.clone()));
14813                        edits.push((suffix_range, empty_str.clone()));
14814                    }
14815                } else {
14816                    continue;
14817                }
14818            }
14819
14820            drop(snapshot);
14821            this.buffer.update(cx, |buffer, cx| {
14822                buffer.edit(edits, None, cx);
14823            });
14824
14825            // Adjust selections so that they end before any comment suffixes that
14826            // were inserted.
14827            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14828            let mut selections = this.selections.all::<Point>(cx);
14829            let snapshot = this.buffer.read(cx).read(cx);
14830            for selection in &mut selections {
14831                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14832                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14833                        Ordering::Less => {
14834                            suffixes_inserted.next();
14835                            continue;
14836                        }
14837                        Ordering::Greater => break,
14838                        Ordering::Equal => {
14839                            if selection.end.column == snapshot.line_len(row) {
14840                                if selection.is_empty() {
14841                                    selection.start.column -= suffix_len as u32;
14842                                }
14843                                selection.end.column -= suffix_len as u32;
14844                            }
14845                            break;
14846                        }
14847                    }
14848                }
14849            }
14850
14851            drop(snapshot);
14852            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14853
14854            let selections = this.selections.all::<Point>(cx);
14855            let selections_on_single_row = selections.windows(2).all(|selections| {
14856                selections[0].start.row == selections[1].start.row
14857                    && selections[0].end.row == selections[1].end.row
14858                    && selections[0].start.row == selections[0].end.row
14859            });
14860            let selections_selecting = selections
14861                .iter()
14862                .any(|selection| selection.start != selection.end);
14863            let advance_downwards = action.advance_downwards
14864                && selections_on_single_row
14865                && !selections_selecting
14866                && !matches!(this.mode, EditorMode::SingleLine);
14867
14868            if advance_downwards {
14869                let snapshot = this.buffer.read(cx).snapshot(cx);
14870
14871                this.change_selections(Default::default(), window, cx, |s| {
14872                    s.move_cursors_with(|display_snapshot, display_point, _| {
14873                        let mut point = display_point.to_point(display_snapshot);
14874                        point.row += 1;
14875                        point = snapshot.clip_point(point, Bias::Left);
14876                        let display_point = point.to_display_point(display_snapshot);
14877                        let goal = SelectionGoal::HorizontalPosition(
14878                            display_snapshot
14879                                .x_for_display_point(display_point, text_layout_details)
14880                                .into(),
14881                        );
14882                        (display_point, goal)
14883                    })
14884                });
14885            }
14886        });
14887    }
14888
14889    pub fn select_enclosing_symbol(
14890        &mut self,
14891        _: &SelectEnclosingSymbol,
14892        window: &mut Window,
14893        cx: &mut Context<Self>,
14894    ) {
14895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14896
14897        let buffer = self.buffer.read(cx).snapshot(cx);
14898        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14899
14900        fn update_selection(
14901            selection: &Selection<usize>,
14902            buffer_snap: &MultiBufferSnapshot,
14903        ) -> Option<Selection<usize>> {
14904            let cursor = selection.head();
14905            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14906            for symbol in symbols.iter().rev() {
14907                let start = symbol.range.start.to_offset(buffer_snap);
14908                let end = symbol.range.end.to_offset(buffer_snap);
14909                let new_range = start..end;
14910                if start < selection.start || end > selection.end {
14911                    return Some(Selection {
14912                        id: selection.id,
14913                        start: new_range.start,
14914                        end: new_range.end,
14915                        goal: SelectionGoal::None,
14916                        reversed: selection.reversed,
14917                    });
14918                }
14919            }
14920            None
14921        }
14922
14923        let mut selected_larger_symbol = false;
14924        let new_selections = old_selections
14925            .iter()
14926            .map(|selection| match update_selection(selection, &buffer) {
14927                Some(new_selection) => {
14928                    if new_selection.range() != selection.range() {
14929                        selected_larger_symbol = true;
14930                    }
14931                    new_selection
14932                }
14933                None => selection.clone(),
14934            })
14935            .collect::<Vec<_>>();
14936
14937        if selected_larger_symbol {
14938            self.change_selections(Default::default(), window, cx, |s| {
14939                s.select(new_selections);
14940            });
14941        }
14942    }
14943
14944    pub fn select_larger_syntax_node(
14945        &mut self,
14946        _: &SelectLargerSyntaxNode,
14947        window: &mut Window,
14948        cx: &mut Context<Self>,
14949    ) {
14950        let Some(visible_row_count) = self.visible_row_count() else {
14951            return;
14952        };
14953        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14954        if old_selections.is_empty() {
14955            return;
14956        }
14957
14958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14959
14960        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14961        let buffer = self.buffer.read(cx).snapshot(cx);
14962
14963        let mut selected_larger_node = false;
14964        let mut new_selections = old_selections
14965            .iter()
14966            .map(|selection| {
14967                let old_range = selection.start..selection.end;
14968
14969                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14970                    // manually select word at selection
14971                    if ["string_content", "inline"].contains(&node.kind()) {
14972                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14973                        // ignore if word is already selected
14974                        if !word_range.is_empty() && old_range != word_range {
14975                            let (last_word_range, _) =
14976                                buffer.surrounding_word(old_range.end, false);
14977                            // only select word if start and end point belongs to same word
14978                            if word_range == last_word_range {
14979                                selected_larger_node = true;
14980                                return Selection {
14981                                    id: selection.id,
14982                                    start: word_range.start,
14983                                    end: word_range.end,
14984                                    goal: SelectionGoal::None,
14985                                    reversed: selection.reversed,
14986                                };
14987                            }
14988                        }
14989                    }
14990                }
14991
14992                let mut new_range = old_range.clone();
14993                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14994                {
14995                    new_range = match containing_range {
14996                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14997                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14998                    };
14999                    if !node.is_named() {
15000                        continue;
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                let child = if selection.is_empty()
15125                    && let Some((_, ancestor_range)) =
15126                        buffer.syntax_ancestor(selection.start..selection.end)
15127                {
15128                    match ancestor_range {
15129                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15130                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15131                    }
15132                } else {
15133                    selection.range()
15134                };
15135
15136                let mut parent = child.clone();
15137                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15138                    parent = match ancestor_range {
15139                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15140                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15141                    };
15142                    if parent.start < child.start || parent.end > child.end {
15143                        break;
15144                    }
15145                }
15146
15147                if parent == child {
15148                    return None;
15149                }
15150                let text = buffer.text_for_range(child).collect::<String>();
15151                Some((selection.id, parent, text))
15152            })
15153            .collect::<Vec<_>>();
15154        if full_edits.is_empty() {
15155            return;
15156        }
15157
15158        self.transact(window, cx, |this, window, cx| {
15159            this.buffer.update(cx, |buffer, cx| {
15160                buffer.edit(
15161                    full_edits
15162                        .iter()
15163                        .map(|(_, p, t)| (p.clone(), t.clone()))
15164                        .collect::<Vec<_>>(),
15165                    None,
15166                    cx,
15167                );
15168            });
15169            this.change_selections(Default::default(), window, cx, |s| {
15170                let mut offset = 0;
15171                let mut selections = vec![];
15172                for (id, parent, text) in full_edits {
15173                    let start = parent.start - offset;
15174                    offset += parent.len() - text.len();
15175                    selections.push(Selection {
15176                        id,
15177                        start,
15178                        end: start + text.len(),
15179                        reversed: false,
15180                        goal: Default::default(),
15181                    });
15182                }
15183                s.select(selections);
15184            });
15185        });
15186    }
15187
15188    pub fn select_next_syntax_node(
15189        &mut self,
15190        _: &SelectNextSyntaxNode,
15191        window: &mut Window,
15192        cx: &mut Context<Self>,
15193    ) {
15194        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15195        if old_selections.is_empty() {
15196            return;
15197        }
15198
15199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15200
15201        let buffer = self.buffer.read(cx).snapshot(cx);
15202        let mut selected_sibling = false;
15203
15204        let new_selections = old_selections
15205            .iter()
15206            .map(|selection| {
15207                let old_range = selection.start..selection.end;
15208
15209                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15210                    let new_range = node.byte_range();
15211                    selected_sibling = true;
15212                    Selection {
15213                        id: selection.id,
15214                        start: new_range.start,
15215                        end: new_range.end,
15216                        goal: SelectionGoal::None,
15217                        reversed: selection.reversed,
15218                    }
15219                } else {
15220                    selection.clone()
15221                }
15222            })
15223            .collect::<Vec<_>>();
15224
15225        if selected_sibling {
15226            self.change_selections(
15227                SelectionEffects::scroll(Autoscroll::fit()),
15228                window,
15229                cx,
15230                |s| {
15231                    s.select(new_selections);
15232                },
15233            );
15234        }
15235    }
15236
15237    pub fn select_prev_syntax_node(
15238        &mut self,
15239        _: &SelectPreviousSyntaxNode,
15240        window: &mut Window,
15241        cx: &mut Context<Self>,
15242    ) {
15243        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15244        if old_selections.is_empty() {
15245            return;
15246        }
15247
15248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15249
15250        let buffer = self.buffer.read(cx).snapshot(cx);
15251        let mut selected_sibling = false;
15252
15253        let new_selections = old_selections
15254            .iter()
15255            .map(|selection| {
15256                let old_range = selection.start..selection.end;
15257
15258                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15259                    let new_range = node.byte_range();
15260                    selected_sibling = true;
15261                    Selection {
15262                        id: selection.id,
15263                        start: new_range.start,
15264                        end: new_range.end,
15265                        goal: SelectionGoal::None,
15266                        reversed: selection.reversed,
15267                    }
15268                } else {
15269                    selection.clone()
15270                }
15271            })
15272            .collect::<Vec<_>>();
15273
15274        if selected_sibling {
15275            self.change_selections(
15276                SelectionEffects::scroll(Autoscroll::fit()),
15277                window,
15278                cx,
15279                |s| {
15280                    s.select(new_selections);
15281                },
15282            );
15283        }
15284    }
15285
15286    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15287        if !EditorSettings::get_global(cx).gutter.runnables {
15288            self.clear_tasks();
15289            return Task::ready(());
15290        }
15291        let project = self.project().map(Entity::downgrade);
15292        let task_sources = self.lsp_task_sources(cx);
15293        let multi_buffer = self.buffer.downgrade();
15294        cx.spawn_in(window, async move |editor, cx| {
15295            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15296            let Some(project) = project.and_then(|p| p.upgrade()) else {
15297                return;
15298            };
15299            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15300                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15301            }) else {
15302                return;
15303            };
15304
15305            let hide_runnables = project
15306                .update(cx, |project, _| project.is_via_collab())
15307                .unwrap_or(true);
15308            if hide_runnables {
15309                return;
15310            }
15311            let new_rows =
15312                cx.background_spawn({
15313                    let snapshot = display_snapshot.clone();
15314                    async move {
15315                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15316                    }
15317                })
15318                    .await;
15319            let Ok(lsp_tasks) =
15320                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15321            else {
15322                return;
15323            };
15324            let lsp_tasks = lsp_tasks.await;
15325
15326            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15327                lsp_tasks
15328                    .into_iter()
15329                    .flat_map(|(kind, tasks)| {
15330                        tasks.into_iter().filter_map(move |(location, task)| {
15331                            Some((kind.clone(), location?, task))
15332                        })
15333                    })
15334                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15335                        let buffer = location.target.buffer;
15336                        let buffer_snapshot = buffer.read(cx).snapshot();
15337                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15338                            |(excerpt_id, snapshot, _)| {
15339                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15340                                    display_snapshot
15341                                        .buffer_snapshot
15342                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15343                                } else {
15344                                    None
15345                                }
15346                            },
15347                        );
15348                        if let Some(offset) = offset {
15349                            let task_buffer_range =
15350                                location.target.range.to_point(&buffer_snapshot);
15351                            let context_buffer_range =
15352                                task_buffer_range.to_offset(&buffer_snapshot);
15353                            let context_range = BufferOffset(context_buffer_range.start)
15354                                ..BufferOffset(context_buffer_range.end);
15355
15356                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15357                                .or_insert_with(|| RunnableTasks {
15358                                    templates: Vec::new(),
15359                                    offset,
15360                                    column: task_buffer_range.start.column,
15361                                    extra_variables: HashMap::default(),
15362                                    context_range,
15363                                })
15364                                .templates
15365                                .push((kind, task.original_task().clone()));
15366                        }
15367
15368                        acc
15369                    })
15370            }) else {
15371                return;
15372            };
15373
15374            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15375                buffer.language_settings(cx).tasks.prefer_lsp
15376            }) else {
15377                return;
15378            };
15379
15380            let rows = Self::runnable_rows(
15381                project,
15382                display_snapshot,
15383                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15384                new_rows,
15385                cx.clone(),
15386            )
15387            .await;
15388            editor
15389                .update(cx, |editor, _| {
15390                    editor.clear_tasks();
15391                    for (key, mut value) in rows {
15392                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15393                            value.templates.extend(lsp_tasks.templates);
15394                        }
15395
15396                        editor.insert_tasks(key, value);
15397                    }
15398                    for (key, value) in lsp_tasks_by_rows {
15399                        editor.insert_tasks(key, value);
15400                    }
15401                })
15402                .ok();
15403        })
15404    }
15405    fn fetch_runnable_ranges(
15406        snapshot: &DisplaySnapshot,
15407        range: Range<Anchor>,
15408    ) -> Vec<language::RunnableRange> {
15409        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15410    }
15411
15412    fn runnable_rows(
15413        project: Entity<Project>,
15414        snapshot: DisplaySnapshot,
15415        prefer_lsp: bool,
15416        runnable_ranges: Vec<RunnableRange>,
15417        cx: AsyncWindowContext,
15418    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15419        cx.spawn(async move |cx| {
15420            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15421            for mut runnable in runnable_ranges {
15422                let Some(tasks) = cx
15423                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15424                    .ok()
15425                else {
15426                    continue;
15427                };
15428                let mut tasks = tasks.await;
15429
15430                if prefer_lsp {
15431                    tasks.retain(|(task_kind, _)| {
15432                        !matches!(task_kind, TaskSourceKind::Language { .. })
15433                    });
15434                }
15435                if tasks.is_empty() {
15436                    continue;
15437                }
15438
15439                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15440                let Some(row) = snapshot
15441                    .buffer_snapshot
15442                    .buffer_line_for_row(MultiBufferRow(point.row))
15443                    .map(|(_, range)| range.start.row)
15444                else {
15445                    continue;
15446                };
15447
15448                let context_range =
15449                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15450                runnable_rows.push((
15451                    (runnable.buffer_id, row),
15452                    RunnableTasks {
15453                        templates: tasks,
15454                        offset: snapshot
15455                            .buffer_snapshot
15456                            .anchor_before(runnable.run_range.start),
15457                        context_range,
15458                        column: point.column,
15459                        extra_variables: runnable.extra_captures,
15460                    },
15461                ));
15462            }
15463            runnable_rows
15464        })
15465    }
15466
15467    fn templates_with_tags(
15468        project: &Entity<Project>,
15469        runnable: &mut Runnable,
15470        cx: &mut App,
15471    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15472        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15473            let (worktree_id, file) = project
15474                .buffer_for_id(runnable.buffer, cx)
15475                .and_then(|buffer| buffer.read(cx).file())
15476                .map(|file| (file.worktree_id(cx), file.clone()))
15477                .unzip();
15478
15479            (
15480                project.task_store().read(cx).task_inventory().cloned(),
15481                worktree_id,
15482                file,
15483            )
15484        });
15485
15486        let tags = mem::take(&mut runnable.tags);
15487        let language = runnable.language.clone();
15488        cx.spawn(async move |cx| {
15489            let mut templates_with_tags = Vec::new();
15490            if let Some(inventory) = inventory {
15491                for RunnableTag(tag) in tags {
15492                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15493                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15494                    }) else {
15495                        return templates_with_tags;
15496                    };
15497                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15498                        move |(_, template)| {
15499                            template.tags.iter().any(|source_tag| source_tag == &tag)
15500                        },
15501                    ));
15502                }
15503            }
15504            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15505
15506            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15507                // Strongest source wins; if we have worktree tag binding, prefer that to
15508                // global and language bindings;
15509                // if we have a global binding, prefer that to language binding.
15510                let first_mismatch = templates_with_tags
15511                    .iter()
15512                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15513                if let Some(index) = first_mismatch {
15514                    templates_with_tags.truncate(index);
15515                }
15516            }
15517
15518            templates_with_tags
15519        })
15520    }
15521
15522    pub fn move_to_enclosing_bracket(
15523        &mut self,
15524        _: &MoveToEnclosingBracket,
15525        window: &mut Window,
15526        cx: &mut Context<Self>,
15527    ) {
15528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15529        self.change_selections(Default::default(), window, cx, |s| {
15530            s.move_offsets_with(|snapshot, selection| {
15531                let Some(enclosing_bracket_ranges) =
15532                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15533                else {
15534                    return;
15535                };
15536
15537                let mut best_length = usize::MAX;
15538                let mut best_inside = false;
15539                let mut best_in_bracket_range = false;
15540                let mut best_destination = None;
15541                for (open, close) in enclosing_bracket_ranges {
15542                    let close = close.to_inclusive();
15543                    let length = close.end() - open.start;
15544                    let inside = selection.start >= open.end && selection.end <= *close.start();
15545                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15546                        || close.contains(&selection.head());
15547
15548                    // If best is next to a bracket and current isn't, skip
15549                    if !in_bracket_range && best_in_bracket_range {
15550                        continue;
15551                    }
15552
15553                    // Prefer smaller lengths unless best is inside and current isn't
15554                    if length > best_length && (best_inside || !inside) {
15555                        continue;
15556                    }
15557
15558                    best_length = length;
15559                    best_inside = inside;
15560                    best_in_bracket_range = in_bracket_range;
15561                    best_destination = Some(
15562                        if close.contains(&selection.start) && close.contains(&selection.end) {
15563                            if inside { open.end } else { open.start }
15564                        } else if inside {
15565                            *close.start()
15566                        } else {
15567                            *close.end()
15568                        },
15569                    );
15570                }
15571
15572                if let Some(destination) = best_destination {
15573                    selection.collapse_to(destination, SelectionGoal::None);
15574                }
15575            })
15576        });
15577    }
15578
15579    pub fn undo_selection(
15580        &mut self,
15581        _: &UndoSelection,
15582        window: &mut Window,
15583        cx: &mut Context<Self>,
15584    ) {
15585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15586        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15587            self.selection_history.mode = SelectionHistoryMode::Undoing;
15588            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15589                this.end_selection(window, cx);
15590                this.change_selections(
15591                    SelectionEffects::scroll(Autoscroll::newest()),
15592                    window,
15593                    cx,
15594                    |s| s.select_anchors(entry.selections.to_vec()),
15595                );
15596            });
15597            self.selection_history.mode = SelectionHistoryMode::Normal;
15598
15599            self.select_next_state = entry.select_next_state;
15600            self.select_prev_state = entry.select_prev_state;
15601            self.add_selections_state = entry.add_selections_state;
15602        }
15603    }
15604
15605    pub fn redo_selection(
15606        &mut self,
15607        _: &RedoSelection,
15608        window: &mut Window,
15609        cx: &mut Context<Self>,
15610    ) {
15611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15612        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15613            self.selection_history.mode = SelectionHistoryMode::Redoing;
15614            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15615                this.end_selection(window, cx);
15616                this.change_selections(
15617                    SelectionEffects::scroll(Autoscroll::newest()),
15618                    window,
15619                    cx,
15620                    |s| s.select_anchors(entry.selections.to_vec()),
15621                );
15622            });
15623            self.selection_history.mode = SelectionHistoryMode::Normal;
15624
15625            self.select_next_state = entry.select_next_state;
15626            self.select_prev_state = entry.select_prev_state;
15627            self.add_selections_state = entry.add_selections_state;
15628        }
15629    }
15630
15631    pub fn expand_excerpts(
15632        &mut self,
15633        action: &ExpandExcerpts,
15634        _: &mut Window,
15635        cx: &mut Context<Self>,
15636    ) {
15637        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15638    }
15639
15640    pub fn expand_excerpts_down(
15641        &mut self,
15642        action: &ExpandExcerptsDown,
15643        _: &mut Window,
15644        cx: &mut Context<Self>,
15645    ) {
15646        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15647    }
15648
15649    pub fn expand_excerpts_up(
15650        &mut self,
15651        action: &ExpandExcerptsUp,
15652        _: &mut Window,
15653        cx: &mut Context<Self>,
15654    ) {
15655        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15656    }
15657
15658    pub fn expand_excerpts_for_direction(
15659        &mut self,
15660        lines: u32,
15661        direction: ExpandExcerptDirection,
15662
15663        cx: &mut Context<Self>,
15664    ) {
15665        let selections = self.selections.disjoint_anchors_arc();
15666
15667        let lines = if lines == 0 {
15668            EditorSettings::get_global(cx).expand_excerpt_lines
15669        } else {
15670            lines
15671        };
15672
15673        self.buffer.update(cx, |buffer, cx| {
15674            let snapshot = buffer.snapshot(cx);
15675            let mut excerpt_ids = selections
15676                .iter()
15677                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15678                .collect::<Vec<_>>();
15679            excerpt_ids.sort();
15680            excerpt_ids.dedup();
15681            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15682        })
15683    }
15684
15685    pub fn expand_excerpt(
15686        &mut self,
15687        excerpt: ExcerptId,
15688        direction: ExpandExcerptDirection,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) {
15692        let current_scroll_position = self.scroll_position(cx);
15693        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15694        let mut should_scroll_up = false;
15695
15696        if direction == ExpandExcerptDirection::Down {
15697            let multi_buffer = self.buffer.read(cx);
15698            let snapshot = multi_buffer.snapshot(cx);
15699            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15700                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15701                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15702            {
15703                let buffer_snapshot = buffer.read(cx).snapshot();
15704                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15705                let last_row = buffer_snapshot.max_point().row;
15706                let lines_below = last_row.saturating_sub(excerpt_end_row);
15707                should_scroll_up = lines_below >= lines_to_expand;
15708            }
15709        }
15710
15711        self.buffer.update(cx, |buffer, cx| {
15712            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15713        });
15714
15715        if should_scroll_up {
15716            let new_scroll_position =
15717                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15718            self.set_scroll_position(new_scroll_position, window, cx);
15719        }
15720    }
15721
15722    pub fn go_to_singleton_buffer_point(
15723        &mut self,
15724        point: Point,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) {
15728        self.go_to_singleton_buffer_range(point..point, window, cx);
15729    }
15730
15731    pub fn go_to_singleton_buffer_range(
15732        &mut self,
15733        range: Range<Point>,
15734        window: &mut Window,
15735        cx: &mut Context<Self>,
15736    ) {
15737        let multibuffer = self.buffer().read(cx);
15738        let Some(buffer) = multibuffer.as_singleton() else {
15739            return;
15740        };
15741        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15742            return;
15743        };
15744        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15745            return;
15746        };
15747        self.change_selections(
15748            SelectionEffects::default().nav_history(true),
15749            window,
15750            cx,
15751            |s| s.select_anchor_ranges([start..end]),
15752        );
15753    }
15754
15755    pub fn go_to_diagnostic(
15756        &mut self,
15757        action: &GoToDiagnostic,
15758        window: &mut Window,
15759        cx: &mut Context<Self>,
15760    ) {
15761        if !self.diagnostics_enabled() {
15762            return;
15763        }
15764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15765        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15766    }
15767
15768    pub fn go_to_prev_diagnostic(
15769        &mut self,
15770        action: &GoToPreviousDiagnostic,
15771        window: &mut Window,
15772        cx: &mut Context<Self>,
15773    ) {
15774        if !self.diagnostics_enabled() {
15775            return;
15776        }
15777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15778        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15779    }
15780
15781    pub fn go_to_diagnostic_impl(
15782        &mut self,
15783        direction: Direction,
15784        severity: GoToDiagnosticSeverityFilter,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        let buffer = self.buffer.read(cx).snapshot(cx);
15789        let selection = self.selections.newest::<usize>(cx);
15790
15791        let mut active_group_id = None;
15792        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15793            && active_group.active_range.start.to_offset(&buffer) == selection.start
15794        {
15795            active_group_id = Some(active_group.group_id);
15796        }
15797
15798        fn filtered(
15799            snapshot: EditorSnapshot,
15800            severity: GoToDiagnosticSeverityFilter,
15801            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15802        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15803            diagnostics
15804                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15805                .filter(|entry| entry.range.start != entry.range.end)
15806                .filter(|entry| !entry.diagnostic.is_unnecessary)
15807                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15808        }
15809
15810        let snapshot = self.snapshot(window, cx);
15811        let before = filtered(
15812            snapshot.clone(),
15813            severity,
15814            buffer
15815                .diagnostics_in_range(0..selection.start)
15816                .filter(|entry| entry.range.start <= selection.start),
15817        );
15818        let after = filtered(
15819            snapshot,
15820            severity,
15821            buffer
15822                .diagnostics_in_range(selection.start..buffer.len())
15823                .filter(|entry| entry.range.start >= selection.start),
15824        );
15825
15826        let mut found: Option<DiagnosticEntry<usize>> = None;
15827        if direction == Direction::Prev {
15828            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15829            {
15830                for diagnostic in prev_diagnostics.into_iter().rev() {
15831                    if diagnostic.range.start != selection.start
15832                        || active_group_id
15833                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15834                    {
15835                        found = Some(diagnostic);
15836                        break 'outer;
15837                    }
15838                }
15839            }
15840        } else {
15841            for diagnostic in after.chain(before) {
15842                if diagnostic.range.start != selection.start
15843                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15844                {
15845                    found = Some(diagnostic);
15846                    break;
15847                }
15848            }
15849        }
15850        let Some(next_diagnostic) = found else {
15851            return;
15852        };
15853
15854        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15855        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15856            return;
15857        };
15858        self.change_selections(Default::default(), window, cx, |s| {
15859            s.select_ranges(vec![
15860                next_diagnostic.range.start..next_diagnostic.range.start,
15861            ])
15862        });
15863        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15864        self.refresh_edit_prediction(false, true, window, cx);
15865    }
15866
15867    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15869        let snapshot = self.snapshot(window, cx);
15870        let selection = self.selections.newest::<Point>(cx);
15871        self.go_to_hunk_before_or_after_position(
15872            &snapshot,
15873            selection.head(),
15874            Direction::Next,
15875            window,
15876            cx,
15877        );
15878    }
15879
15880    pub fn go_to_hunk_before_or_after_position(
15881        &mut self,
15882        snapshot: &EditorSnapshot,
15883        position: Point,
15884        direction: Direction,
15885        window: &mut Window,
15886        cx: &mut Context<Editor>,
15887    ) {
15888        let row = if direction == Direction::Next {
15889            self.hunk_after_position(snapshot, position)
15890                .map(|hunk| hunk.row_range.start)
15891        } else {
15892            self.hunk_before_position(snapshot, position)
15893        };
15894
15895        if let Some(row) = row {
15896            let destination = Point::new(row.0, 0);
15897            let autoscroll = Autoscroll::center();
15898
15899            self.unfold_ranges(&[destination..destination], false, false, cx);
15900            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15901                s.select_ranges([destination..destination]);
15902            });
15903        }
15904    }
15905
15906    fn hunk_after_position(
15907        &mut self,
15908        snapshot: &EditorSnapshot,
15909        position: Point,
15910    ) -> Option<MultiBufferDiffHunk> {
15911        snapshot
15912            .buffer_snapshot
15913            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15914            .find(|hunk| hunk.row_range.start.0 > position.row)
15915            .or_else(|| {
15916                snapshot
15917                    .buffer_snapshot
15918                    .diff_hunks_in_range(Point::zero()..position)
15919                    .find(|hunk| hunk.row_range.end.0 < position.row)
15920            })
15921    }
15922
15923    fn go_to_prev_hunk(
15924        &mut self,
15925        _: &GoToPreviousHunk,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) {
15929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15930        let snapshot = self.snapshot(window, cx);
15931        let selection = self.selections.newest::<Point>(cx);
15932        self.go_to_hunk_before_or_after_position(
15933            &snapshot,
15934            selection.head(),
15935            Direction::Prev,
15936            window,
15937            cx,
15938        );
15939    }
15940
15941    fn hunk_before_position(
15942        &mut self,
15943        snapshot: &EditorSnapshot,
15944        position: Point,
15945    ) -> Option<MultiBufferRow> {
15946        snapshot
15947            .buffer_snapshot
15948            .diff_hunk_before(position)
15949            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15950    }
15951
15952    fn go_to_next_change(
15953        &mut self,
15954        _: &GoToNextChange,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        if let Some(selections) = self
15959            .change_list
15960            .next_change(1, Direction::Next)
15961            .map(|s| s.to_vec())
15962        {
15963            self.change_selections(Default::default(), window, cx, |s| {
15964                let map = s.display_map();
15965                s.select_display_ranges(selections.iter().map(|a| {
15966                    let point = a.to_display_point(&map);
15967                    point..point
15968                }))
15969            })
15970        }
15971    }
15972
15973    fn go_to_previous_change(
15974        &mut self,
15975        _: &GoToPreviousChange,
15976        window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) {
15979        if let Some(selections) = self
15980            .change_list
15981            .next_change(1, Direction::Prev)
15982            .map(|s| s.to_vec())
15983        {
15984            self.change_selections(Default::default(), window, cx, |s| {
15985                let map = s.display_map();
15986                s.select_display_ranges(selections.iter().map(|a| {
15987                    let point = a.to_display_point(&map);
15988                    point..point
15989                }))
15990            })
15991        }
15992    }
15993
15994    pub fn go_to_next_document_highlight(
15995        &mut self,
15996        _: &GoToNextDocumentHighlight,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16001    }
16002
16003    pub fn go_to_prev_document_highlight(
16004        &mut self,
16005        _: &GoToPreviousDocumentHighlight,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16010    }
16011
16012    pub fn go_to_document_highlight_before_or_after_position(
16013        &mut self,
16014        direction: Direction,
16015        window: &mut Window,
16016        cx: &mut Context<Editor>,
16017    ) {
16018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16019        let snapshot = self.snapshot(window, cx);
16020        let buffer = &snapshot.buffer_snapshot;
16021        let position = self.selections.newest::<Point>(cx).head();
16022        let anchor_position = buffer.anchor_after(position);
16023
16024        // Get all document highlights (both read and write)
16025        let mut all_highlights = Vec::new();
16026
16027        if let Some((_, read_highlights)) = self
16028            .background_highlights
16029            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16030        {
16031            all_highlights.extend(read_highlights.iter());
16032        }
16033
16034        if let Some((_, write_highlights)) = self
16035            .background_highlights
16036            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16037        {
16038            all_highlights.extend(write_highlights.iter());
16039        }
16040
16041        if all_highlights.is_empty() {
16042            return;
16043        }
16044
16045        // Sort highlights by position
16046        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16047
16048        let target_highlight = match direction {
16049            Direction::Next => {
16050                // Find the first highlight after the current position
16051                all_highlights
16052                    .iter()
16053                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16054            }
16055            Direction::Prev => {
16056                // Find the last highlight before the current position
16057                all_highlights
16058                    .iter()
16059                    .rev()
16060                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16061            }
16062        };
16063
16064        if let Some(highlight) = target_highlight {
16065            let destination = highlight.start.to_point(buffer);
16066            let autoscroll = Autoscroll::center();
16067
16068            self.unfold_ranges(&[destination..destination], false, false, cx);
16069            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16070                s.select_ranges([destination..destination]);
16071            });
16072        }
16073    }
16074
16075    fn go_to_line<T: 'static>(
16076        &mut self,
16077        position: Anchor,
16078        highlight_color: Option<Hsla>,
16079        window: &mut Window,
16080        cx: &mut Context<Self>,
16081    ) {
16082        let snapshot = self.snapshot(window, cx).display_snapshot;
16083        let position = position.to_point(&snapshot.buffer_snapshot);
16084        let start = snapshot
16085            .buffer_snapshot
16086            .clip_point(Point::new(position.row, 0), Bias::Left);
16087        let end = start + Point::new(1, 0);
16088        let start = snapshot.buffer_snapshot.anchor_before(start);
16089        let end = snapshot.buffer_snapshot.anchor_before(end);
16090
16091        self.highlight_rows::<T>(
16092            start..end,
16093            highlight_color
16094                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16095            Default::default(),
16096            cx,
16097        );
16098
16099        if self.buffer.read(cx).is_singleton() {
16100            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16101        }
16102    }
16103
16104    pub fn go_to_definition(
16105        &mut self,
16106        _: &GoToDefinition,
16107        window: &mut Window,
16108        cx: &mut Context<Self>,
16109    ) -> Task<Result<Navigated>> {
16110        let definition =
16111            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16112        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16113        cx.spawn_in(window, async move |editor, cx| {
16114            if definition.await? == Navigated::Yes {
16115                return Ok(Navigated::Yes);
16116            }
16117            match fallback_strategy {
16118                GoToDefinitionFallback::None => Ok(Navigated::No),
16119                GoToDefinitionFallback::FindAllReferences => {
16120                    match editor.update_in(cx, |editor, window, cx| {
16121                        editor.find_all_references(&FindAllReferences, window, cx)
16122                    })? {
16123                        Some(references) => references.await,
16124                        None => Ok(Navigated::No),
16125                    }
16126                }
16127            }
16128        })
16129    }
16130
16131    pub fn go_to_declaration(
16132        &mut self,
16133        _: &GoToDeclaration,
16134        window: &mut Window,
16135        cx: &mut Context<Self>,
16136    ) -> Task<Result<Navigated>> {
16137        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16138    }
16139
16140    pub fn go_to_declaration_split(
16141        &mut self,
16142        _: &GoToDeclaration,
16143        window: &mut Window,
16144        cx: &mut Context<Self>,
16145    ) -> Task<Result<Navigated>> {
16146        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16147    }
16148
16149    pub fn go_to_implementation(
16150        &mut self,
16151        _: &GoToImplementation,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) -> Task<Result<Navigated>> {
16155        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16156    }
16157
16158    pub fn go_to_implementation_split(
16159        &mut self,
16160        _: &GoToImplementationSplit,
16161        window: &mut Window,
16162        cx: &mut Context<Self>,
16163    ) -> Task<Result<Navigated>> {
16164        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16165    }
16166
16167    pub fn go_to_type_definition(
16168        &mut self,
16169        _: &GoToTypeDefinition,
16170        window: &mut Window,
16171        cx: &mut Context<Self>,
16172    ) -> Task<Result<Navigated>> {
16173        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16174    }
16175
16176    pub fn go_to_definition_split(
16177        &mut self,
16178        _: &GoToDefinitionSplit,
16179        window: &mut Window,
16180        cx: &mut Context<Self>,
16181    ) -> Task<Result<Navigated>> {
16182        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16183    }
16184
16185    pub fn go_to_type_definition_split(
16186        &mut self,
16187        _: &GoToTypeDefinitionSplit,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) -> Task<Result<Navigated>> {
16191        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16192    }
16193
16194    fn go_to_definition_of_kind(
16195        &mut self,
16196        kind: GotoDefinitionKind,
16197        split: bool,
16198        window: &mut Window,
16199        cx: &mut Context<Self>,
16200    ) -> Task<Result<Navigated>> {
16201        let Some(provider) = self.semantics_provider.clone() else {
16202            return Task::ready(Ok(Navigated::No));
16203        };
16204        let head = self.selections.newest::<usize>(cx).head();
16205        let buffer = self.buffer.read(cx);
16206        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16207            return Task::ready(Ok(Navigated::No));
16208        };
16209        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16210            return Task::ready(Ok(Navigated::No));
16211        };
16212
16213        cx.spawn_in(window, async move |editor, cx| {
16214            let Some(definitions) = definitions.await? else {
16215                return Ok(Navigated::No);
16216            };
16217            let navigated = editor
16218                .update_in(cx, |editor, window, cx| {
16219                    editor.navigate_to_hover_links(
16220                        Some(kind),
16221                        definitions
16222                            .into_iter()
16223                            .filter(|location| {
16224                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16225                            })
16226                            .map(HoverLink::Text)
16227                            .collect::<Vec<_>>(),
16228                        split,
16229                        window,
16230                        cx,
16231                    )
16232                })?
16233                .await?;
16234            anyhow::Ok(navigated)
16235        })
16236    }
16237
16238    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16239        let selection = self.selections.newest_anchor();
16240        let head = selection.head();
16241        let tail = selection.tail();
16242
16243        let Some((buffer, start_position)) =
16244            self.buffer.read(cx).text_anchor_for_position(head, cx)
16245        else {
16246            return;
16247        };
16248
16249        let end_position = if head != tail {
16250            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16251                return;
16252            };
16253            Some(pos)
16254        } else {
16255            None
16256        };
16257
16258        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16259            let url = if let Some(end_pos) = end_position {
16260                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16261            } else {
16262                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16263            };
16264
16265            if let Some(url) = url {
16266                editor.update(cx, |_, cx| {
16267                    cx.open_url(&url);
16268                })
16269            } else {
16270                Ok(())
16271            }
16272        });
16273
16274        url_finder.detach();
16275    }
16276
16277    pub fn open_selected_filename(
16278        &mut self,
16279        _: &OpenSelectedFilename,
16280        window: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) {
16283        let Some(workspace) = self.workspace() else {
16284            return;
16285        };
16286
16287        let position = self.selections.newest_anchor().head();
16288
16289        let Some((buffer, buffer_position)) =
16290            self.buffer.read(cx).text_anchor_for_position(position, cx)
16291        else {
16292            return;
16293        };
16294
16295        let project = self.project.clone();
16296
16297        cx.spawn_in(window, async move |_, cx| {
16298            let result = find_file(&buffer, project, buffer_position, cx).await;
16299
16300            if let Some((_, path)) = result {
16301                workspace
16302                    .update_in(cx, |workspace, window, cx| {
16303                        workspace.open_resolved_path(path, window, cx)
16304                    })?
16305                    .await?;
16306            }
16307            anyhow::Ok(())
16308        })
16309        .detach();
16310    }
16311
16312    pub(crate) fn navigate_to_hover_links(
16313        &mut self,
16314        kind: Option<GotoDefinitionKind>,
16315        definitions: Vec<HoverLink>,
16316        split: bool,
16317        window: &mut Window,
16318        cx: &mut Context<Editor>,
16319    ) -> Task<Result<Navigated>> {
16320        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16321        let mut first_url_or_file = None;
16322        let definitions: Vec<_> = definitions
16323            .into_iter()
16324            .filter_map(|def| match def {
16325                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16326                HoverLink::InlayHint(lsp_location, server_id) => {
16327                    let computation =
16328                        self.compute_target_location(lsp_location, server_id, window, cx);
16329                    Some(cx.background_spawn(computation))
16330                }
16331                HoverLink::Url(url) => {
16332                    first_url_or_file = Some(Either::Left(url));
16333                    None
16334                }
16335                HoverLink::File(path) => {
16336                    first_url_or_file = Some(Either::Right(path));
16337                    None
16338                }
16339            })
16340            .collect();
16341
16342        let workspace = self.workspace();
16343
16344        cx.spawn_in(window, async move |editor, acx| {
16345            let mut locations: Vec<Location> = future::join_all(definitions)
16346                .await
16347                .into_iter()
16348                .filter_map(|location| location.transpose())
16349                .collect::<Result<_>>()
16350                .context("location tasks")?;
16351
16352            if locations.len() > 1 {
16353                let Some(workspace) = workspace else {
16354                    return Ok(Navigated::No);
16355                };
16356
16357                let tab_kind = match kind {
16358                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16359                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16360                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16361                    Some(GotoDefinitionKind::Type) => "Types",
16362                };
16363                let title = editor
16364                    .update_in(acx, |_, _, cx| {
16365                        let target = locations
16366                            .iter()
16367                            .map(|location| {
16368                                location
16369                                    .buffer
16370                                    .read(cx)
16371                                    .text_for_range(location.range.clone())
16372                                    .collect::<String>()
16373                            })
16374                            .filter(|text| !text.contains('\n'))
16375                            .unique()
16376                            .take(3)
16377                            .join(", ");
16378                        if target.is_empty() {
16379                            tab_kind.to_owned()
16380                        } else {
16381                            format!("{tab_kind} for {target}")
16382                        }
16383                    })
16384                    .context("buffer title")?;
16385
16386                let opened = workspace
16387                    .update_in(acx, |workspace, window, cx| {
16388                        Self::open_locations_in_multibuffer(
16389                            workspace,
16390                            locations,
16391                            title,
16392                            split,
16393                            MultibufferSelectionMode::First,
16394                            window,
16395                            cx,
16396                        )
16397                    })
16398                    .is_ok();
16399
16400                anyhow::Ok(Navigated::from_bool(opened))
16401            } else if locations.is_empty() {
16402                // If there is one url or file, open it directly
16403                match first_url_or_file {
16404                    Some(Either::Left(url)) => {
16405                        acx.update(|_, cx| cx.open_url(&url))?;
16406                        Ok(Navigated::Yes)
16407                    }
16408                    Some(Either::Right(path)) => {
16409                        let Some(workspace) = workspace else {
16410                            return Ok(Navigated::No);
16411                        };
16412
16413                        workspace
16414                            .update_in(acx, |workspace, window, cx| {
16415                                workspace.open_resolved_path(path, window, cx)
16416                            })?
16417                            .await?;
16418                        Ok(Navigated::Yes)
16419                    }
16420                    None => Ok(Navigated::No),
16421                }
16422            } else {
16423                let Some(workspace) = workspace else {
16424                    return Ok(Navigated::No);
16425                };
16426
16427                let target = locations.pop().unwrap();
16428                editor.update_in(acx, |editor, window, cx| {
16429                    let range = target.range.to_point(target.buffer.read(cx));
16430                    let range = editor.range_for_match(&range);
16431                    let range = collapse_multiline_range(range);
16432
16433                    if !split
16434                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16435                    {
16436                        editor.go_to_singleton_buffer_range(range, window, cx);
16437                    } else {
16438                        let pane = workspace.read(cx).active_pane().clone();
16439                        window.defer(cx, move |window, cx| {
16440                            let target_editor: Entity<Self> =
16441                                workspace.update(cx, |workspace, cx| {
16442                                    let pane = if split {
16443                                        workspace.adjacent_pane(window, cx)
16444                                    } else {
16445                                        workspace.active_pane().clone()
16446                                    };
16447
16448                                    workspace.open_project_item(
16449                                        pane,
16450                                        target.buffer.clone(),
16451                                        true,
16452                                        true,
16453                                        window,
16454                                        cx,
16455                                    )
16456                                });
16457                            target_editor.update(cx, |target_editor, cx| {
16458                                // When selecting a definition in a different buffer, disable the nav history
16459                                // to avoid creating a history entry at the previous cursor location.
16460                                pane.update(cx, |pane, _| pane.disable_history());
16461                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16462                                pane.update(cx, |pane, _| pane.enable_history());
16463                            });
16464                        });
16465                    }
16466                    Navigated::Yes
16467                })
16468            }
16469        })
16470    }
16471
16472    fn compute_target_location(
16473        &self,
16474        lsp_location: lsp::Location,
16475        server_id: LanguageServerId,
16476        window: &mut Window,
16477        cx: &mut Context<Self>,
16478    ) -> Task<anyhow::Result<Option<Location>>> {
16479        let Some(project) = self.project.clone() else {
16480            return Task::ready(Ok(None));
16481        };
16482
16483        cx.spawn_in(window, async move |editor, cx| {
16484            let location_task = editor.update(cx, |_, cx| {
16485                project.update(cx, |project, cx| {
16486                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16487                })
16488            })?;
16489            let location = Some({
16490                let target_buffer_handle = location_task.await.context("open local buffer")?;
16491                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16492                    let target_start = target_buffer
16493                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16494                    let target_end = target_buffer
16495                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16496                    target_buffer.anchor_after(target_start)
16497                        ..target_buffer.anchor_before(target_end)
16498                })?;
16499                Location {
16500                    buffer: target_buffer_handle,
16501                    range,
16502                }
16503            });
16504            Ok(location)
16505        })
16506    }
16507
16508    pub fn find_all_references(
16509        &mut self,
16510        _: &FindAllReferences,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) -> Option<Task<Result<Navigated>>> {
16514        let selection = self.selections.newest::<usize>(cx);
16515        let multi_buffer = self.buffer.read(cx);
16516        let head = selection.head();
16517
16518        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16519        let head_anchor = multi_buffer_snapshot.anchor_at(
16520            head,
16521            if head < selection.tail() {
16522                Bias::Right
16523            } else {
16524                Bias::Left
16525            },
16526        );
16527
16528        match self
16529            .find_all_references_task_sources
16530            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16531        {
16532            Ok(_) => {
16533                log::info!(
16534                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16535                );
16536                return None;
16537            }
16538            Err(i) => {
16539                self.find_all_references_task_sources.insert(i, head_anchor);
16540            }
16541        }
16542
16543        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16544        let workspace = self.workspace()?;
16545        let project = workspace.read(cx).project().clone();
16546        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16547        Some(cx.spawn_in(window, async move |editor, cx| {
16548            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16549                if let Ok(i) = editor
16550                    .find_all_references_task_sources
16551                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16552                {
16553                    editor.find_all_references_task_sources.remove(i);
16554                }
16555            });
16556
16557            let Some(locations) = references.await? else {
16558                return anyhow::Ok(Navigated::No);
16559            };
16560            if locations.is_empty() {
16561                return anyhow::Ok(Navigated::No);
16562            }
16563
16564            workspace.update_in(cx, |workspace, window, cx| {
16565                let target = locations
16566                    .iter()
16567                    .map(|location| {
16568                        location
16569                            .buffer
16570                            .read(cx)
16571                            .text_for_range(location.range.clone())
16572                            .collect::<String>()
16573                    })
16574                    .filter(|text| !text.contains('\n'))
16575                    .unique()
16576                    .take(3)
16577                    .join(", ");
16578                let title = if target.is_empty() {
16579                    "References".to_owned()
16580                } else {
16581                    format!("References to {target}")
16582                };
16583                Self::open_locations_in_multibuffer(
16584                    workspace,
16585                    locations,
16586                    title,
16587                    false,
16588                    MultibufferSelectionMode::First,
16589                    window,
16590                    cx,
16591                );
16592                Navigated::Yes
16593            })
16594        }))
16595    }
16596
16597    /// Opens a multibuffer with the given project locations in it
16598    pub fn open_locations_in_multibuffer(
16599        workspace: &mut Workspace,
16600        mut locations: Vec<Location>,
16601        title: String,
16602        split: bool,
16603        multibuffer_selection_mode: MultibufferSelectionMode,
16604        window: &mut Window,
16605        cx: &mut Context<Workspace>,
16606    ) {
16607        if locations.is_empty() {
16608            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16609            return;
16610        }
16611
16612        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16613
16614        let mut locations = locations.into_iter().peekable();
16615        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16616        let capability = workspace.project().read(cx).capability();
16617
16618        // a key to find existing multibuffer editors with the same set of locations
16619        // to prevent us from opening more and more multibuffer tabs for searches and the like
16620        let mut key = (title.clone(), vec![]);
16621        let excerpt_buffer = cx.new(|cx| {
16622            let key = &mut key.1;
16623            let mut multibuffer = MultiBuffer::new(capability);
16624            while let Some(location) = locations.next() {
16625                let buffer = location.buffer.read(cx);
16626                let mut ranges_for_buffer = Vec::new();
16627                let range = location.range.to_point(buffer);
16628                ranges_for_buffer.push(range.clone());
16629
16630                while let Some(next_location) =
16631                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16632                {
16633                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16634                }
16635
16636                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16637                key.push((
16638                    location.buffer.read(cx).remote_id(),
16639                    ranges_for_buffer.clone(),
16640                ));
16641                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16642                    PathKey::for_buffer(&location.buffer, cx),
16643                    location.buffer.clone(),
16644                    ranges_for_buffer,
16645                    multibuffer_context_lines(cx),
16646                    cx,
16647                );
16648                ranges.extend(new_ranges)
16649            }
16650
16651            multibuffer.with_title(title)
16652        });
16653        let existing = workspace.active_pane().update(cx, |pane, cx| {
16654            pane.items()
16655                .filter_map(|item| item.downcast::<Editor>())
16656                .find(|editor| {
16657                    editor
16658                        .read(cx)
16659                        .lookup_key
16660                        .as_ref()
16661                        .and_then(|it| {
16662                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16663                        })
16664                        .is_some_and(|it| *it == key)
16665                })
16666        });
16667        let editor = existing.unwrap_or_else(|| {
16668            cx.new(|cx| {
16669                let mut editor = Editor::for_multibuffer(
16670                    excerpt_buffer,
16671                    Some(workspace.project().clone()),
16672                    window,
16673                    cx,
16674                );
16675                editor.lookup_key = Some(Box::new(key));
16676                editor
16677            })
16678        });
16679        editor.update(cx, |editor, cx| {
16680            match multibuffer_selection_mode {
16681                MultibufferSelectionMode::First => {
16682                    if let Some(first_range) = ranges.first() {
16683                        editor.change_selections(
16684                            SelectionEffects::no_scroll(),
16685                            window,
16686                            cx,
16687                            |selections| {
16688                                selections.clear_disjoint();
16689                                selections
16690                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16691                            },
16692                        );
16693                    }
16694                    editor.highlight_background::<Self>(
16695                        &ranges,
16696                        |theme| theme.colors().editor_highlighted_line_background,
16697                        cx,
16698                    );
16699                }
16700                MultibufferSelectionMode::All => {
16701                    editor.change_selections(
16702                        SelectionEffects::no_scroll(),
16703                        window,
16704                        cx,
16705                        |selections| {
16706                            selections.clear_disjoint();
16707                            selections.select_anchor_ranges(ranges);
16708                        },
16709                    );
16710                }
16711            }
16712            editor.register_buffers_with_language_servers(cx);
16713        });
16714
16715        let item = Box::new(editor);
16716        let item_id = item.item_id();
16717
16718        if split {
16719            workspace.split_item(SplitDirection::Right, item, window, cx);
16720        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16721            let (preview_item_id, preview_item_idx) =
16722                workspace.active_pane().read_with(cx, |pane, _| {
16723                    (pane.preview_item_id(), pane.preview_item_idx())
16724                });
16725
16726            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16727
16728            if let Some(preview_item_id) = preview_item_id {
16729                workspace.active_pane().update(cx, |pane, cx| {
16730                    pane.remove_item(preview_item_id, false, false, window, cx);
16731                });
16732            }
16733        } else {
16734            workspace.add_item_to_active_pane(item, None, true, window, cx);
16735        }
16736        workspace.active_pane().update(cx, |pane, cx| {
16737            pane.set_preview_item_id(Some(item_id), cx);
16738        });
16739    }
16740
16741    pub fn rename(
16742        &mut self,
16743        _: &Rename,
16744        window: &mut Window,
16745        cx: &mut Context<Self>,
16746    ) -> Option<Task<Result<()>>> {
16747        use language::ToOffset as _;
16748
16749        let provider = self.semantics_provider.clone()?;
16750        let selection = self.selections.newest_anchor().clone();
16751        let (cursor_buffer, cursor_buffer_position) = self
16752            .buffer
16753            .read(cx)
16754            .text_anchor_for_position(selection.head(), cx)?;
16755        let (tail_buffer, cursor_buffer_position_end) = self
16756            .buffer
16757            .read(cx)
16758            .text_anchor_for_position(selection.tail(), cx)?;
16759        if tail_buffer != cursor_buffer {
16760            return None;
16761        }
16762
16763        let snapshot = cursor_buffer.read(cx).snapshot();
16764        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16765        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16766        let prepare_rename = provider
16767            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16768            .unwrap_or_else(|| Task::ready(Ok(None)));
16769        drop(snapshot);
16770
16771        Some(cx.spawn_in(window, async move |this, cx| {
16772            let rename_range = if let Some(range) = prepare_rename.await? {
16773                Some(range)
16774            } else {
16775                this.update(cx, |this, cx| {
16776                    let buffer = this.buffer.read(cx).snapshot(cx);
16777                    let mut buffer_highlights = this
16778                        .document_highlights_for_position(selection.head(), &buffer)
16779                        .filter(|highlight| {
16780                            highlight.start.excerpt_id == selection.head().excerpt_id
16781                                && highlight.end.excerpt_id == selection.head().excerpt_id
16782                        });
16783                    buffer_highlights
16784                        .next()
16785                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16786                })?
16787            };
16788            if let Some(rename_range) = rename_range {
16789                this.update_in(cx, |this, window, cx| {
16790                    let snapshot = cursor_buffer.read(cx).snapshot();
16791                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16792                    let cursor_offset_in_rename_range =
16793                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16794                    let cursor_offset_in_rename_range_end =
16795                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16796
16797                    this.take_rename(false, window, cx);
16798                    let buffer = this.buffer.read(cx).read(cx);
16799                    let cursor_offset = selection.head().to_offset(&buffer);
16800                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16801                    let rename_end = rename_start + rename_buffer_range.len();
16802                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16803                    let mut old_highlight_id = None;
16804                    let old_name: Arc<str> = buffer
16805                        .chunks(rename_start..rename_end, true)
16806                        .map(|chunk| {
16807                            if old_highlight_id.is_none() {
16808                                old_highlight_id = chunk.syntax_highlight_id;
16809                            }
16810                            chunk.text
16811                        })
16812                        .collect::<String>()
16813                        .into();
16814
16815                    drop(buffer);
16816
16817                    // Position the selection in the rename editor so that it matches the current selection.
16818                    this.show_local_selections = false;
16819                    let rename_editor = cx.new(|cx| {
16820                        let mut editor = Editor::single_line(window, cx);
16821                        editor.buffer.update(cx, |buffer, cx| {
16822                            buffer.edit([(0..0, old_name.clone())], None, cx)
16823                        });
16824                        let rename_selection_range = match cursor_offset_in_rename_range
16825                            .cmp(&cursor_offset_in_rename_range_end)
16826                        {
16827                            Ordering::Equal => {
16828                                editor.select_all(&SelectAll, window, cx);
16829                                return editor;
16830                            }
16831                            Ordering::Less => {
16832                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16833                            }
16834                            Ordering::Greater => {
16835                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16836                            }
16837                        };
16838                        if rename_selection_range.end > old_name.len() {
16839                            editor.select_all(&SelectAll, window, cx);
16840                        } else {
16841                            editor.change_selections(Default::default(), window, cx, |s| {
16842                                s.select_ranges([rename_selection_range]);
16843                            });
16844                        }
16845                        editor
16846                    });
16847                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16848                        if e == &EditorEvent::Focused {
16849                            cx.emit(EditorEvent::FocusedIn)
16850                        }
16851                    })
16852                    .detach();
16853
16854                    let write_highlights =
16855                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16856                    let read_highlights =
16857                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16858                    let ranges = write_highlights
16859                        .iter()
16860                        .flat_map(|(_, ranges)| ranges.iter())
16861                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16862                        .cloned()
16863                        .collect();
16864
16865                    this.highlight_text::<Rename>(
16866                        ranges,
16867                        HighlightStyle {
16868                            fade_out: Some(0.6),
16869                            ..Default::default()
16870                        },
16871                        cx,
16872                    );
16873                    let rename_focus_handle = rename_editor.focus_handle(cx);
16874                    window.focus(&rename_focus_handle);
16875                    let block_id = this.insert_blocks(
16876                        [BlockProperties {
16877                            style: BlockStyle::Flex,
16878                            placement: BlockPlacement::Below(range.start),
16879                            height: Some(1),
16880                            render: Arc::new({
16881                                let rename_editor = rename_editor.clone();
16882                                move |cx: &mut BlockContext| {
16883                                    let mut text_style = cx.editor_style.text.clone();
16884                                    if let Some(highlight_style) = old_highlight_id
16885                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16886                                    {
16887                                        text_style = text_style.highlight(highlight_style);
16888                                    }
16889                                    div()
16890                                        .block_mouse_except_scroll()
16891                                        .pl(cx.anchor_x)
16892                                        .child(EditorElement::new(
16893                                            &rename_editor,
16894                                            EditorStyle {
16895                                                background: cx.theme().system().transparent,
16896                                                local_player: cx.editor_style.local_player,
16897                                                text: text_style,
16898                                                scrollbar_width: cx.editor_style.scrollbar_width,
16899                                                syntax: cx.editor_style.syntax.clone(),
16900                                                status: cx.editor_style.status.clone(),
16901                                                inlay_hints_style: HighlightStyle {
16902                                                    font_weight: Some(FontWeight::BOLD),
16903                                                    ..make_inlay_hints_style(cx.app)
16904                                                },
16905                                                edit_prediction_styles: make_suggestion_styles(
16906                                                    cx.app,
16907                                                ),
16908                                                ..EditorStyle::default()
16909                                            },
16910                                        ))
16911                                        .into_any_element()
16912                                }
16913                            }),
16914                            priority: 0,
16915                        }],
16916                        Some(Autoscroll::fit()),
16917                        cx,
16918                    )[0];
16919                    this.pending_rename = Some(RenameState {
16920                        range,
16921                        old_name,
16922                        editor: rename_editor,
16923                        block_id,
16924                    });
16925                })?;
16926            }
16927
16928            Ok(())
16929        }))
16930    }
16931
16932    pub fn confirm_rename(
16933        &mut self,
16934        _: &ConfirmRename,
16935        window: &mut Window,
16936        cx: &mut Context<Self>,
16937    ) -> Option<Task<Result<()>>> {
16938        let rename = self.take_rename(false, window, cx)?;
16939        let workspace = self.workspace()?.downgrade();
16940        let (buffer, start) = self
16941            .buffer
16942            .read(cx)
16943            .text_anchor_for_position(rename.range.start, cx)?;
16944        let (end_buffer, _) = self
16945            .buffer
16946            .read(cx)
16947            .text_anchor_for_position(rename.range.end, cx)?;
16948        if buffer != end_buffer {
16949            return None;
16950        }
16951
16952        let old_name = rename.old_name;
16953        let new_name = rename.editor.read(cx).text(cx);
16954
16955        let rename = self.semantics_provider.as_ref()?.perform_rename(
16956            &buffer,
16957            start,
16958            new_name.clone(),
16959            cx,
16960        )?;
16961
16962        Some(cx.spawn_in(window, async move |editor, cx| {
16963            let project_transaction = rename.await?;
16964            Self::open_project_transaction(
16965                &editor,
16966                workspace,
16967                project_transaction,
16968                format!("Rename: {}{}", old_name, new_name),
16969                cx,
16970            )
16971            .await?;
16972
16973            editor.update(cx, |editor, cx| {
16974                editor.refresh_document_highlights(cx);
16975            })?;
16976            Ok(())
16977        }))
16978    }
16979
16980    fn take_rename(
16981        &mut self,
16982        moving_cursor: bool,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) -> Option<RenameState> {
16986        let rename = self.pending_rename.take()?;
16987        if rename.editor.focus_handle(cx).is_focused(window) {
16988            window.focus(&self.focus_handle);
16989        }
16990
16991        self.remove_blocks(
16992            [rename.block_id].into_iter().collect(),
16993            Some(Autoscroll::fit()),
16994            cx,
16995        );
16996        self.clear_highlights::<Rename>(cx);
16997        self.show_local_selections = true;
16998
16999        if moving_cursor {
17000            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17001                editor.selections.newest::<usize>(cx).head()
17002            });
17003
17004            // Update the selection to match the position of the selection inside
17005            // the rename editor.
17006            let snapshot = self.buffer.read(cx).read(cx);
17007            let rename_range = rename.range.to_offset(&snapshot);
17008            let cursor_in_editor = snapshot
17009                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17010                .min(rename_range.end);
17011            drop(snapshot);
17012
17013            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17014                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17015            });
17016        } else {
17017            self.refresh_document_highlights(cx);
17018        }
17019
17020        Some(rename)
17021    }
17022
17023    pub fn pending_rename(&self) -> Option<&RenameState> {
17024        self.pending_rename.as_ref()
17025    }
17026
17027    fn format(
17028        &mut self,
17029        _: &Format,
17030        window: &mut Window,
17031        cx: &mut Context<Self>,
17032    ) -> Option<Task<Result<()>>> {
17033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17034
17035        let project = match &self.project {
17036            Some(project) => project.clone(),
17037            None => return None,
17038        };
17039
17040        Some(self.perform_format(
17041            project,
17042            FormatTrigger::Manual,
17043            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17044            window,
17045            cx,
17046        ))
17047    }
17048
17049    fn format_selections(
17050        &mut self,
17051        _: &FormatSelections,
17052        window: &mut Window,
17053        cx: &mut Context<Self>,
17054    ) -> Option<Task<Result<()>>> {
17055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17056
17057        let project = match &self.project {
17058            Some(project) => project.clone(),
17059            None => return None,
17060        };
17061
17062        let ranges = self
17063            .selections
17064            .all_adjusted(cx)
17065            .into_iter()
17066            .map(|selection| selection.range())
17067            .collect_vec();
17068
17069        Some(self.perform_format(
17070            project,
17071            FormatTrigger::Manual,
17072            FormatTarget::Ranges(ranges),
17073            window,
17074            cx,
17075        ))
17076    }
17077
17078    fn perform_format(
17079        &mut self,
17080        project: Entity<Project>,
17081        trigger: FormatTrigger,
17082        target: FormatTarget,
17083        window: &mut Window,
17084        cx: &mut Context<Self>,
17085    ) -> Task<Result<()>> {
17086        let buffer = self.buffer.clone();
17087        let (buffers, target) = match target {
17088            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17089            FormatTarget::Ranges(selection_ranges) => {
17090                let multi_buffer = buffer.read(cx);
17091                let snapshot = multi_buffer.read(cx);
17092                let mut buffers = HashSet::default();
17093                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17094                    BTreeMap::new();
17095                for selection_range in selection_ranges {
17096                    for (buffer, buffer_range, _) in
17097                        snapshot.range_to_buffer_ranges(selection_range)
17098                    {
17099                        let buffer_id = buffer.remote_id();
17100                        let start = buffer.anchor_before(buffer_range.start);
17101                        let end = buffer.anchor_after(buffer_range.end);
17102                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17103                        buffer_id_to_ranges
17104                            .entry(buffer_id)
17105                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17106                            .or_insert_with(|| vec![start..end]);
17107                    }
17108                }
17109                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17110            }
17111        };
17112
17113        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17114        let selections_prev = transaction_id_prev
17115            .and_then(|transaction_id_prev| {
17116                // default to selections as they were after the last edit, if we have them,
17117                // instead of how they are now.
17118                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17119                // will take you back to where you made the last edit, instead of staying where you scrolled
17120                self.selection_history
17121                    .transaction(transaction_id_prev)
17122                    .map(|t| t.0.clone())
17123            })
17124            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17125
17126        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17127        let format = project.update(cx, |project, cx| {
17128            project.format(buffers, target, true, trigger, cx)
17129        });
17130
17131        cx.spawn_in(window, async move |editor, cx| {
17132            let transaction = futures::select_biased! {
17133                transaction = format.log_err().fuse() => transaction,
17134                () = timeout => {
17135                    log::warn!("timed out waiting for formatting");
17136                    None
17137                }
17138            };
17139
17140            buffer
17141                .update(cx, |buffer, cx| {
17142                    if let Some(transaction) = transaction
17143                        && !buffer.is_singleton()
17144                    {
17145                        buffer.push_transaction(&transaction.0, cx);
17146                    }
17147                    cx.notify();
17148                })
17149                .ok();
17150
17151            if let Some(transaction_id_now) =
17152                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17153            {
17154                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17155                if has_new_transaction {
17156                    _ = editor.update(cx, |editor, _| {
17157                        editor
17158                            .selection_history
17159                            .insert_transaction(transaction_id_now, selections_prev);
17160                    });
17161                }
17162            }
17163
17164            Ok(())
17165        })
17166    }
17167
17168    fn organize_imports(
17169        &mut self,
17170        _: &OrganizeImports,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) -> Option<Task<Result<()>>> {
17174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17175        let project = match &self.project {
17176            Some(project) => project.clone(),
17177            None => return None,
17178        };
17179        Some(self.perform_code_action_kind(
17180            project,
17181            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17182            window,
17183            cx,
17184        ))
17185    }
17186
17187    fn perform_code_action_kind(
17188        &mut self,
17189        project: Entity<Project>,
17190        kind: CodeActionKind,
17191        window: &mut Window,
17192        cx: &mut Context<Self>,
17193    ) -> Task<Result<()>> {
17194        let buffer = self.buffer.clone();
17195        let buffers = buffer.read(cx).all_buffers();
17196        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17197        let apply_action = project.update(cx, |project, cx| {
17198            project.apply_code_action_kind(buffers, kind, true, cx)
17199        });
17200        cx.spawn_in(window, async move |_, cx| {
17201            let transaction = futures::select_biased! {
17202                () = timeout => {
17203                    log::warn!("timed out waiting for executing code action");
17204                    None
17205                }
17206                transaction = apply_action.log_err().fuse() => transaction,
17207            };
17208            buffer
17209                .update(cx, |buffer, cx| {
17210                    // check if we need this
17211                    if let Some(transaction) = transaction
17212                        && !buffer.is_singleton()
17213                    {
17214                        buffer.push_transaction(&transaction.0, cx);
17215                    }
17216                    cx.notify();
17217                })
17218                .ok();
17219            Ok(())
17220        })
17221    }
17222
17223    pub fn restart_language_server(
17224        &mut self,
17225        _: &RestartLanguageServer,
17226        _: &mut Window,
17227        cx: &mut Context<Self>,
17228    ) {
17229        if let Some(project) = self.project.clone() {
17230            self.buffer.update(cx, |multi_buffer, cx| {
17231                project.update(cx, |project, cx| {
17232                    project.restart_language_servers_for_buffers(
17233                        multi_buffer.all_buffers().into_iter().collect(),
17234                        HashSet::default(),
17235                        cx,
17236                    );
17237                });
17238            })
17239        }
17240    }
17241
17242    pub fn stop_language_server(
17243        &mut self,
17244        _: &StopLanguageServer,
17245        _: &mut Window,
17246        cx: &mut Context<Self>,
17247    ) {
17248        if let Some(project) = self.project.clone() {
17249            self.buffer.update(cx, |multi_buffer, cx| {
17250                project.update(cx, |project, cx| {
17251                    project.stop_language_servers_for_buffers(
17252                        multi_buffer.all_buffers().into_iter().collect(),
17253                        HashSet::default(),
17254                        cx,
17255                    );
17256                    cx.emit(project::Event::RefreshInlayHints);
17257                });
17258            });
17259        }
17260    }
17261
17262    fn cancel_language_server_work(
17263        workspace: &mut Workspace,
17264        _: &actions::CancelLanguageServerWork,
17265        _: &mut Window,
17266        cx: &mut Context<Workspace>,
17267    ) {
17268        let project = workspace.project();
17269        let buffers = workspace
17270            .active_item(cx)
17271            .and_then(|item| item.act_as::<Editor>(cx))
17272            .map_or(HashSet::default(), |editor| {
17273                editor.read(cx).buffer.read(cx).all_buffers()
17274            });
17275        project.update(cx, |project, cx| {
17276            project.cancel_language_server_work_for_buffers(buffers, cx);
17277        });
17278    }
17279
17280    fn show_character_palette(
17281        &mut self,
17282        _: &ShowCharacterPalette,
17283        window: &mut Window,
17284        _: &mut Context<Self>,
17285    ) {
17286        window.show_character_palette();
17287    }
17288
17289    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17290        if !self.diagnostics_enabled() {
17291            return;
17292        }
17293
17294        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17295            let buffer = self.buffer.read(cx).snapshot(cx);
17296            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17297            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17298            let is_valid = buffer
17299                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17300                .any(|entry| {
17301                    entry.diagnostic.is_primary
17302                        && !entry.range.is_empty()
17303                        && entry.range.start == primary_range_start
17304                        && entry.diagnostic.message == active_diagnostics.active_message
17305                });
17306
17307            if !is_valid {
17308                self.dismiss_diagnostics(cx);
17309            }
17310        }
17311    }
17312
17313    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17314        match &self.active_diagnostics {
17315            ActiveDiagnostic::Group(group) => Some(group),
17316            _ => None,
17317        }
17318    }
17319
17320    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17321        if !self.diagnostics_enabled() {
17322            return;
17323        }
17324        self.dismiss_diagnostics(cx);
17325        self.active_diagnostics = ActiveDiagnostic::All;
17326    }
17327
17328    fn activate_diagnostics(
17329        &mut self,
17330        buffer_id: BufferId,
17331        diagnostic: DiagnosticEntry<usize>,
17332        window: &mut Window,
17333        cx: &mut Context<Self>,
17334    ) {
17335        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17336            return;
17337        }
17338        self.dismiss_diagnostics(cx);
17339        let snapshot = self.snapshot(window, cx);
17340        let buffer = self.buffer.read(cx).snapshot(cx);
17341        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17342            return;
17343        };
17344
17345        let diagnostic_group = buffer
17346            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17347            .collect::<Vec<_>>();
17348
17349        let blocks =
17350            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17351
17352        let blocks = self.display_map.update(cx, |display_map, cx| {
17353            display_map.insert_blocks(blocks, cx).into_iter().collect()
17354        });
17355        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17356            active_range: buffer.anchor_before(diagnostic.range.start)
17357                ..buffer.anchor_after(diagnostic.range.end),
17358            active_message: diagnostic.diagnostic.message.clone(),
17359            group_id: diagnostic.diagnostic.group_id,
17360            blocks,
17361        });
17362        cx.notify();
17363    }
17364
17365    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17366        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17367            return;
17368        };
17369
17370        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17371        if let ActiveDiagnostic::Group(group) = prev {
17372            self.display_map.update(cx, |display_map, cx| {
17373                display_map.remove_blocks(group.blocks, cx);
17374            });
17375            cx.notify();
17376        }
17377    }
17378
17379    /// Disable inline diagnostics rendering for this editor.
17380    pub fn disable_inline_diagnostics(&mut self) {
17381        self.inline_diagnostics_enabled = false;
17382        self.inline_diagnostics_update = Task::ready(());
17383        self.inline_diagnostics.clear();
17384    }
17385
17386    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17387        self.diagnostics_enabled = false;
17388        self.dismiss_diagnostics(cx);
17389        self.inline_diagnostics_update = Task::ready(());
17390        self.inline_diagnostics.clear();
17391    }
17392
17393    pub fn disable_word_completions(&mut self) {
17394        self.word_completions_enabled = false;
17395    }
17396
17397    pub fn diagnostics_enabled(&self) -> bool {
17398        self.diagnostics_enabled && self.mode.is_full()
17399    }
17400
17401    pub fn inline_diagnostics_enabled(&self) -> bool {
17402        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17403    }
17404
17405    pub fn show_inline_diagnostics(&self) -> bool {
17406        self.show_inline_diagnostics
17407    }
17408
17409    pub fn toggle_inline_diagnostics(
17410        &mut self,
17411        _: &ToggleInlineDiagnostics,
17412        window: &mut Window,
17413        cx: &mut Context<Editor>,
17414    ) {
17415        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17416        self.refresh_inline_diagnostics(false, window, cx);
17417    }
17418
17419    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17420        self.diagnostics_max_severity = severity;
17421        self.display_map.update(cx, |display_map, _| {
17422            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17423        });
17424    }
17425
17426    pub fn toggle_diagnostics(
17427        &mut self,
17428        _: &ToggleDiagnostics,
17429        window: &mut Window,
17430        cx: &mut Context<Editor>,
17431    ) {
17432        if !self.diagnostics_enabled() {
17433            return;
17434        }
17435
17436        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17437            EditorSettings::get_global(cx)
17438                .diagnostics_max_severity
17439                .filter(|severity| severity != &DiagnosticSeverity::Off)
17440                .unwrap_or(DiagnosticSeverity::Hint)
17441        } else {
17442            DiagnosticSeverity::Off
17443        };
17444        self.set_max_diagnostics_severity(new_severity, cx);
17445        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17446            self.active_diagnostics = ActiveDiagnostic::None;
17447            self.inline_diagnostics_update = Task::ready(());
17448            self.inline_diagnostics.clear();
17449        } else {
17450            self.refresh_inline_diagnostics(false, window, cx);
17451        }
17452
17453        cx.notify();
17454    }
17455
17456    pub fn toggle_minimap(
17457        &mut self,
17458        _: &ToggleMinimap,
17459        window: &mut Window,
17460        cx: &mut Context<Editor>,
17461    ) {
17462        if self.supports_minimap(cx) {
17463            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17464        }
17465    }
17466
17467    fn refresh_inline_diagnostics(
17468        &mut self,
17469        debounce: bool,
17470        window: &mut Window,
17471        cx: &mut Context<Self>,
17472    ) {
17473        let max_severity = ProjectSettings::get_global(cx)
17474            .diagnostics
17475            .inline
17476            .max_severity
17477            .unwrap_or(self.diagnostics_max_severity);
17478
17479        if !self.inline_diagnostics_enabled()
17480            || !self.show_inline_diagnostics
17481            || max_severity == DiagnosticSeverity::Off
17482        {
17483            self.inline_diagnostics_update = Task::ready(());
17484            self.inline_diagnostics.clear();
17485            return;
17486        }
17487
17488        let debounce_ms = ProjectSettings::get_global(cx)
17489            .diagnostics
17490            .inline
17491            .update_debounce_ms;
17492        let debounce = if debounce && debounce_ms > 0 {
17493            Some(Duration::from_millis(debounce_ms))
17494        } else {
17495            None
17496        };
17497        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17498            if let Some(debounce) = debounce {
17499                cx.background_executor().timer(debounce).await;
17500            }
17501            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17502                editor
17503                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17504                    .ok()
17505            }) else {
17506                return;
17507            };
17508
17509            let new_inline_diagnostics = cx
17510                .background_spawn(async move {
17511                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17512                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17513                        let message = diagnostic_entry
17514                            .diagnostic
17515                            .message
17516                            .split_once('\n')
17517                            .map(|(line, _)| line)
17518                            .map(SharedString::new)
17519                            .unwrap_or_else(|| {
17520                                SharedString::from(diagnostic_entry.diagnostic.message)
17521                            });
17522                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17523                        let (Ok(i) | Err(i)) = inline_diagnostics
17524                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17525                        inline_diagnostics.insert(
17526                            i,
17527                            (
17528                                start_anchor,
17529                                InlineDiagnostic {
17530                                    message,
17531                                    group_id: diagnostic_entry.diagnostic.group_id,
17532                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17533                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17534                                    severity: diagnostic_entry.diagnostic.severity,
17535                                },
17536                            ),
17537                        );
17538                    }
17539                    inline_diagnostics
17540                })
17541                .await;
17542
17543            editor
17544                .update(cx, |editor, cx| {
17545                    editor.inline_diagnostics = new_inline_diagnostics;
17546                    cx.notify();
17547                })
17548                .ok();
17549        });
17550    }
17551
17552    fn pull_diagnostics(
17553        &mut self,
17554        buffer_id: Option<BufferId>,
17555        window: &Window,
17556        cx: &mut Context<Self>,
17557    ) -> Option<()> {
17558        if !self.mode().is_full() {
17559            return None;
17560        }
17561        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17562            .diagnostics
17563            .lsp_pull_diagnostics;
17564        if !pull_diagnostics_settings.enabled {
17565            return None;
17566        }
17567        let project = self.project()?.downgrade();
17568        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17569        let mut buffers = self.buffer.read(cx).all_buffers();
17570        if let Some(buffer_id) = buffer_id {
17571            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17572        }
17573
17574        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17575            cx.background_executor().timer(debounce).await;
17576
17577            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17578                buffers
17579                    .into_iter()
17580                    .filter_map(|buffer| {
17581                        project
17582                            .update(cx, |project, cx| {
17583                                project.lsp_store().update(cx, |lsp_store, cx| {
17584                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17585                                })
17586                            })
17587                            .ok()
17588                    })
17589                    .collect::<FuturesUnordered<_>>()
17590            }) else {
17591                return;
17592            };
17593
17594            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17595                match pull_task {
17596                    Ok(()) => {
17597                        if editor
17598                            .update_in(cx, |editor, window, cx| {
17599                                editor.update_diagnostics_state(window, cx);
17600                            })
17601                            .is_err()
17602                        {
17603                            return;
17604                        }
17605                    }
17606                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17607                }
17608            }
17609        });
17610
17611        Some(())
17612    }
17613
17614    pub fn set_selections_from_remote(
17615        &mut self,
17616        selections: Vec<Selection<Anchor>>,
17617        pending_selection: Option<Selection<Anchor>>,
17618        window: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        let old_cursor_position = self.selections.newest_anchor().head();
17622        self.selections.change_with(cx, |s| {
17623            s.select_anchors(selections);
17624            if let Some(pending_selection) = pending_selection {
17625                s.set_pending(pending_selection, SelectMode::Character);
17626            } else {
17627                s.clear_pending();
17628            }
17629        });
17630        self.selections_did_change(
17631            false,
17632            &old_cursor_position,
17633            SelectionEffects::default(),
17634            window,
17635            cx,
17636        );
17637    }
17638
17639    pub fn transact(
17640        &mut self,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17644    ) -> Option<TransactionId> {
17645        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17646            this.start_transaction_at(Instant::now(), window, cx);
17647            update(this, window, cx);
17648            this.end_transaction_at(Instant::now(), cx)
17649        })
17650    }
17651
17652    pub fn start_transaction_at(
17653        &mut self,
17654        now: Instant,
17655        window: &mut Window,
17656        cx: &mut Context<Self>,
17657    ) -> Option<TransactionId> {
17658        self.end_selection(window, cx);
17659        if let Some(tx_id) = self
17660            .buffer
17661            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17662        {
17663            self.selection_history
17664                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17665            cx.emit(EditorEvent::TransactionBegun {
17666                transaction_id: tx_id,
17667            });
17668            Some(tx_id)
17669        } else {
17670            None
17671        }
17672    }
17673
17674    pub fn end_transaction_at(
17675        &mut self,
17676        now: Instant,
17677        cx: &mut Context<Self>,
17678    ) -> Option<TransactionId> {
17679        if let Some(transaction_id) = self
17680            .buffer
17681            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17682        {
17683            if let Some((_, end_selections)) =
17684                self.selection_history.transaction_mut(transaction_id)
17685            {
17686                *end_selections = Some(self.selections.disjoint_anchors_arc());
17687            } else {
17688                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17689            }
17690
17691            cx.emit(EditorEvent::Edited { transaction_id });
17692            Some(transaction_id)
17693        } else {
17694            None
17695        }
17696    }
17697
17698    pub fn modify_transaction_selection_history(
17699        &mut self,
17700        transaction_id: TransactionId,
17701        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17702    ) -> bool {
17703        self.selection_history
17704            .transaction_mut(transaction_id)
17705            .map(modify)
17706            .is_some()
17707    }
17708
17709    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17710        if self.selection_mark_mode {
17711            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17712                s.move_with(|_, sel| {
17713                    sel.collapse_to(sel.head(), SelectionGoal::None);
17714                });
17715            })
17716        }
17717        self.selection_mark_mode = true;
17718        cx.notify();
17719    }
17720
17721    pub fn swap_selection_ends(
17722        &mut self,
17723        _: &actions::SwapSelectionEnds,
17724        window: &mut Window,
17725        cx: &mut Context<Self>,
17726    ) {
17727        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17728            s.move_with(|_, sel| {
17729                if sel.start != sel.end {
17730                    sel.reversed = !sel.reversed
17731                }
17732            });
17733        });
17734        self.request_autoscroll(Autoscroll::newest(), cx);
17735        cx.notify();
17736    }
17737
17738    pub fn toggle_focus(
17739        workspace: &mut Workspace,
17740        _: &actions::ToggleFocus,
17741        window: &mut Window,
17742        cx: &mut Context<Workspace>,
17743    ) {
17744        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17745            return;
17746        };
17747        workspace.activate_item(&item, true, true, window, cx);
17748    }
17749
17750    pub fn toggle_fold(
17751        &mut self,
17752        _: &actions::ToggleFold,
17753        window: &mut Window,
17754        cx: &mut Context<Self>,
17755    ) {
17756        if self.is_singleton(cx) {
17757            let selection = self.selections.newest::<Point>(cx);
17758
17759            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17760            let range = if selection.is_empty() {
17761                let point = selection.head().to_display_point(&display_map);
17762                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17763                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17764                    .to_point(&display_map);
17765                start..end
17766            } else {
17767                selection.range()
17768            };
17769            if display_map.folds_in_range(range).next().is_some() {
17770                self.unfold_lines(&Default::default(), window, cx)
17771            } else {
17772                self.fold(&Default::default(), window, cx)
17773            }
17774        } else {
17775            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17776            let buffer_ids: HashSet<_> = self
17777                .selections
17778                .disjoint_anchor_ranges()
17779                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17780                .collect();
17781
17782            let should_unfold = buffer_ids
17783                .iter()
17784                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17785
17786            for buffer_id in buffer_ids {
17787                if should_unfold {
17788                    self.unfold_buffer(buffer_id, cx);
17789                } else {
17790                    self.fold_buffer(buffer_id, cx);
17791                }
17792            }
17793        }
17794    }
17795
17796    pub fn toggle_fold_recursive(
17797        &mut self,
17798        _: &actions::ToggleFoldRecursive,
17799        window: &mut Window,
17800        cx: &mut Context<Self>,
17801    ) {
17802        let selection = self.selections.newest::<Point>(cx);
17803
17804        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17805        let range = if selection.is_empty() {
17806            let point = selection.head().to_display_point(&display_map);
17807            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17808            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17809                .to_point(&display_map);
17810            start..end
17811        } else {
17812            selection.range()
17813        };
17814        if display_map.folds_in_range(range).next().is_some() {
17815            self.unfold_recursive(&Default::default(), window, cx)
17816        } else {
17817            self.fold_recursive(&Default::default(), window, cx)
17818        }
17819    }
17820
17821    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17822        if self.is_singleton(cx) {
17823            let mut to_fold = Vec::new();
17824            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17825            let selections = self.selections.all_adjusted(cx);
17826
17827            for selection in selections {
17828                let range = selection.range().sorted();
17829                let buffer_start_row = range.start.row;
17830
17831                if range.start.row != range.end.row {
17832                    let mut found = false;
17833                    let mut row = range.start.row;
17834                    while row <= range.end.row {
17835                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17836                        {
17837                            found = true;
17838                            row = crease.range().end.row + 1;
17839                            to_fold.push(crease);
17840                        } else {
17841                            row += 1
17842                        }
17843                    }
17844                    if found {
17845                        continue;
17846                    }
17847                }
17848
17849                for row in (0..=range.start.row).rev() {
17850                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17851                        && crease.range().end.row >= buffer_start_row
17852                    {
17853                        to_fold.push(crease);
17854                        if row <= range.start.row {
17855                            break;
17856                        }
17857                    }
17858                }
17859            }
17860
17861            self.fold_creases(to_fold, true, window, cx);
17862        } else {
17863            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17864            let buffer_ids = self
17865                .selections
17866                .disjoint_anchor_ranges()
17867                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17868                .collect::<HashSet<_>>();
17869            for buffer_id in buffer_ids {
17870                self.fold_buffer(buffer_id, cx);
17871            }
17872        }
17873    }
17874
17875    pub fn toggle_fold_all(
17876        &mut self,
17877        _: &actions::ToggleFoldAll,
17878        window: &mut Window,
17879        cx: &mut Context<Self>,
17880    ) {
17881        if self.buffer.read(cx).is_singleton() {
17882            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17883            let has_folds = display_map
17884                .folds_in_range(0..display_map.buffer_snapshot.len())
17885                .next()
17886                .is_some();
17887
17888            if has_folds {
17889                self.unfold_all(&actions::UnfoldAll, window, cx);
17890            } else {
17891                self.fold_all(&actions::FoldAll, window, cx);
17892            }
17893        } else {
17894            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17895            let should_unfold = buffer_ids
17896                .iter()
17897                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17898
17899            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17900                editor
17901                    .update_in(cx, |editor, _, cx| {
17902                        for buffer_id in buffer_ids {
17903                            if should_unfold {
17904                                editor.unfold_buffer(buffer_id, cx);
17905                            } else {
17906                                editor.fold_buffer(buffer_id, cx);
17907                            }
17908                        }
17909                    })
17910                    .ok();
17911            });
17912        }
17913    }
17914
17915    fn fold_at_level(
17916        &mut self,
17917        fold_at: &FoldAtLevel,
17918        window: &mut Window,
17919        cx: &mut Context<Self>,
17920    ) {
17921        if !self.buffer.read(cx).is_singleton() {
17922            return;
17923        }
17924
17925        let fold_at_level = fold_at.0;
17926        let snapshot = self.buffer.read(cx).snapshot(cx);
17927        let mut to_fold = Vec::new();
17928        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17929
17930        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17931            while start_row < end_row {
17932                match self
17933                    .snapshot(window, cx)
17934                    .crease_for_buffer_row(MultiBufferRow(start_row))
17935                {
17936                    Some(crease) => {
17937                        let nested_start_row = crease.range().start.row + 1;
17938                        let nested_end_row = crease.range().end.row;
17939
17940                        if current_level < fold_at_level {
17941                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17942                        } else if current_level == fold_at_level {
17943                            to_fold.push(crease);
17944                        }
17945
17946                        start_row = nested_end_row + 1;
17947                    }
17948                    None => start_row += 1,
17949                }
17950            }
17951        }
17952
17953        self.fold_creases(to_fold, true, window, cx);
17954    }
17955
17956    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17957        if self.buffer.read(cx).is_singleton() {
17958            let mut fold_ranges = Vec::new();
17959            let snapshot = self.buffer.read(cx).snapshot(cx);
17960
17961            for row in 0..snapshot.max_row().0 {
17962                if let Some(foldable_range) = self
17963                    .snapshot(window, cx)
17964                    .crease_for_buffer_row(MultiBufferRow(row))
17965                {
17966                    fold_ranges.push(foldable_range);
17967                }
17968            }
17969
17970            self.fold_creases(fold_ranges, true, window, cx);
17971        } else {
17972            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17973                editor
17974                    .update_in(cx, |editor, _, cx| {
17975                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17976                            editor.fold_buffer(buffer_id, cx);
17977                        }
17978                    })
17979                    .ok();
17980            });
17981        }
17982    }
17983
17984    pub fn fold_function_bodies(
17985        &mut self,
17986        _: &actions::FoldFunctionBodies,
17987        window: &mut Window,
17988        cx: &mut Context<Self>,
17989    ) {
17990        let snapshot = self.buffer.read(cx).snapshot(cx);
17991
17992        let ranges = snapshot
17993            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17994            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17995            .collect::<Vec<_>>();
17996
17997        let creases = ranges
17998            .into_iter()
17999            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18000            .collect();
18001
18002        self.fold_creases(creases, true, window, cx);
18003    }
18004
18005    pub fn fold_recursive(
18006        &mut self,
18007        _: &actions::FoldRecursive,
18008        window: &mut Window,
18009        cx: &mut Context<Self>,
18010    ) {
18011        let mut to_fold = Vec::new();
18012        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18013        let selections = self.selections.all_adjusted(cx);
18014
18015        for selection in selections {
18016            let range = selection.range().sorted();
18017            let buffer_start_row = range.start.row;
18018
18019            if range.start.row != range.end.row {
18020                let mut found = false;
18021                for row in range.start.row..=range.end.row {
18022                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18023                        found = true;
18024                        to_fold.push(crease);
18025                    }
18026                }
18027                if found {
18028                    continue;
18029                }
18030            }
18031
18032            for row in (0..=range.start.row).rev() {
18033                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18034                    if crease.range().end.row >= buffer_start_row {
18035                        to_fold.push(crease);
18036                    } else {
18037                        break;
18038                    }
18039                }
18040            }
18041        }
18042
18043        self.fold_creases(to_fold, true, window, cx);
18044    }
18045
18046    pub fn fold_at(
18047        &mut self,
18048        buffer_row: MultiBufferRow,
18049        window: &mut Window,
18050        cx: &mut Context<Self>,
18051    ) {
18052        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18053
18054        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18055            let autoscroll = self
18056                .selections
18057                .all::<Point>(cx)
18058                .iter()
18059                .any(|selection| crease.range().overlaps(&selection.range()));
18060
18061            self.fold_creases(vec![crease], autoscroll, window, cx);
18062        }
18063    }
18064
18065    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18066        if self.is_singleton(cx) {
18067            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18068            let buffer = &display_map.buffer_snapshot;
18069            let selections = self.selections.all::<Point>(cx);
18070            let ranges = selections
18071                .iter()
18072                .map(|s| {
18073                    let range = s.display_range(&display_map).sorted();
18074                    let mut start = range.start.to_point(&display_map);
18075                    let mut end = range.end.to_point(&display_map);
18076                    start.column = 0;
18077                    end.column = buffer.line_len(MultiBufferRow(end.row));
18078                    start..end
18079                })
18080                .collect::<Vec<_>>();
18081
18082            self.unfold_ranges(&ranges, true, true, cx);
18083        } else {
18084            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18085            let buffer_ids = self
18086                .selections
18087                .disjoint_anchor_ranges()
18088                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18089                .collect::<HashSet<_>>();
18090            for buffer_id in buffer_ids {
18091                self.unfold_buffer(buffer_id, cx);
18092            }
18093        }
18094    }
18095
18096    pub fn unfold_recursive(
18097        &mut self,
18098        _: &UnfoldRecursive,
18099        _window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) {
18102        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18103        let selections = self.selections.all::<Point>(cx);
18104        let ranges = selections
18105            .iter()
18106            .map(|s| {
18107                let mut range = s.display_range(&display_map).sorted();
18108                *range.start.column_mut() = 0;
18109                *range.end.column_mut() = display_map.line_len(range.end.row());
18110                let start = range.start.to_point(&display_map);
18111                let end = range.end.to_point(&display_map);
18112                start..end
18113            })
18114            .collect::<Vec<_>>();
18115
18116        self.unfold_ranges(&ranges, true, true, cx);
18117    }
18118
18119    pub fn unfold_at(
18120        &mut self,
18121        buffer_row: MultiBufferRow,
18122        _window: &mut Window,
18123        cx: &mut Context<Self>,
18124    ) {
18125        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126
18127        let intersection_range = Point::new(buffer_row.0, 0)
18128            ..Point::new(
18129                buffer_row.0,
18130                display_map.buffer_snapshot.line_len(buffer_row),
18131            );
18132
18133        let autoscroll = self
18134            .selections
18135            .all::<Point>(cx)
18136            .iter()
18137            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18138
18139        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18140    }
18141
18142    pub fn unfold_all(
18143        &mut self,
18144        _: &actions::UnfoldAll,
18145        _window: &mut Window,
18146        cx: &mut Context<Self>,
18147    ) {
18148        if self.buffer.read(cx).is_singleton() {
18149            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18150            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18151        } else {
18152            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18153                editor
18154                    .update(cx, |editor, cx| {
18155                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18156                            editor.unfold_buffer(buffer_id, cx);
18157                        }
18158                    })
18159                    .ok();
18160            });
18161        }
18162    }
18163
18164    pub fn fold_selected_ranges(
18165        &mut self,
18166        _: &FoldSelectedRanges,
18167        window: &mut Window,
18168        cx: &mut Context<Self>,
18169    ) {
18170        let selections = self.selections.all_adjusted(cx);
18171        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18172        let ranges = selections
18173            .into_iter()
18174            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18175            .collect::<Vec<_>>();
18176        self.fold_creases(ranges, true, window, cx);
18177    }
18178
18179    pub fn fold_ranges<T: ToOffset + Clone>(
18180        &mut self,
18181        ranges: Vec<Range<T>>,
18182        auto_scroll: bool,
18183        window: &mut Window,
18184        cx: &mut Context<Self>,
18185    ) {
18186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18187        let ranges = ranges
18188            .into_iter()
18189            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18190            .collect::<Vec<_>>();
18191        self.fold_creases(ranges, auto_scroll, window, cx);
18192    }
18193
18194    pub fn fold_creases<T: ToOffset + Clone>(
18195        &mut self,
18196        creases: Vec<Crease<T>>,
18197        auto_scroll: bool,
18198        _window: &mut Window,
18199        cx: &mut Context<Self>,
18200    ) {
18201        if creases.is_empty() {
18202            return;
18203        }
18204
18205        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18206
18207        if auto_scroll {
18208            self.request_autoscroll(Autoscroll::fit(), cx);
18209        }
18210
18211        cx.notify();
18212
18213        self.scrollbar_marker_state.dirty = true;
18214        self.folds_did_change(cx);
18215    }
18216
18217    /// Removes any folds whose ranges intersect any of the given ranges.
18218    pub fn unfold_ranges<T: ToOffset + Clone>(
18219        &mut self,
18220        ranges: &[Range<T>],
18221        inclusive: bool,
18222        auto_scroll: bool,
18223        cx: &mut Context<Self>,
18224    ) {
18225        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18226            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18227        });
18228        self.folds_did_change(cx);
18229    }
18230
18231    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18232        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18233            return;
18234        }
18235        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18236        self.display_map.update(cx, |display_map, cx| {
18237            display_map.fold_buffers([buffer_id], cx)
18238        });
18239        cx.emit(EditorEvent::BufferFoldToggled {
18240            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18241            folded: true,
18242        });
18243        cx.notify();
18244    }
18245
18246    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18247        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18248            return;
18249        }
18250        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18251        self.display_map.update(cx, |display_map, cx| {
18252            display_map.unfold_buffers([buffer_id], cx);
18253        });
18254        cx.emit(EditorEvent::BufferFoldToggled {
18255            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18256            folded: false,
18257        });
18258        cx.notify();
18259    }
18260
18261    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18262        self.display_map.read(cx).is_buffer_folded(buffer)
18263    }
18264
18265    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18266        self.display_map.read(cx).folded_buffers()
18267    }
18268
18269    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18270        self.display_map.update(cx, |display_map, cx| {
18271            display_map.disable_header_for_buffer(buffer_id, cx);
18272        });
18273        cx.notify();
18274    }
18275
18276    /// Removes any folds with the given ranges.
18277    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18278        &mut self,
18279        ranges: &[Range<T>],
18280        type_id: TypeId,
18281        auto_scroll: bool,
18282        cx: &mut Context<Self>,
18283    ) {
18284        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18285            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18286        });
18287        self.folds_did_change(cx);
18288    }
18289
18290    fn remove_folds_with<T: ToOffset + Clone>(
18291        &mut self,
18292        ranges: &[Range<T>],
18293        auto_scroll: bool,
18294        cx: &mut Context<Self>,
18295        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18296    ) {
18297        if ranges.is_empty() {
18298            return;
18299        }
18300
18301        let mut buffers_affected = HashSet::default();
18302        let multi_buffer = self.buffer().read(cx);
18303        for range in ranges {
18304            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18305                buffers_affected.insert(buffer.read(cx).remote_id());
18306            };
18307        }
18308
18309        self.display_map.update(cx, update);
18310
18311        if auto_scroll {
18312            self.request_autoscroll(Autoscroll::fit(), cx);
18313        }
18314
18315        cx.notify();
18316        self.scrollbar_marker_state.dirty = true;
18317        self.active_indent_guides_state.dirty = true;
18318    }
18319
18320    pub fn update_renderer_widths(
18321        &mut self,
18322        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18323        cx: &mut Context<Self>,
18324    ) -> bool {
18325        self.display_map
18326            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18327    }
18328
18329    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18330        self.display_map.read(cx).fold_placeholder.clone()
18331    }
18332
18333    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18334        self.buffer.update(cx, |buffer, cx| {
18335            buffer.set_all_diff_hunks_expanded(cx);
18336        });
18337    }
18338
18339    pub fn expand_all_diff_hunks(
18340        &mut self,
18341        _: &ExpandAllDiffHunks,
18342        _window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        self.buffer.update(cx, |buffer, cx| {
18346            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18347        });
18348    }
18349
18350    pub fn toggle_selected_diff_hunks(
18351        &mut self,
18352        _: &ToggleSelectedDiffHunks,
18353        _window: &mut Window,
18354        cx: &mut Context<Self>,
18355    ) {
18356        let ranges: Vec<_> = self
18357            .selections
18358            .disjoint_anchors()
18359            .iter()
18360            .map(|s| s.range())
18361            .collect();
18362        self.toggle_diff_hunks_in_ranges(ranges, cx);
18363    }
18364
18365    pub fn diff_hunks_in_ranges<'a>(
18366        &'a self,
18367        ranges: &'a [Range<Anchor>],
18368        buffer: &'a MultiBufferSnapshot,
18369    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18370        ranges.iter().flat_map(move |range| {
18371            let end_excerpt_id = range.end.excerpt_id;
18372            let range = range.to_point(buffer);
18373            let mut peek_end = range.end;
18374            if range.end.row < buffer.max_row().0 {
18375                peek_end = Point::new(range.end.row + 1, 0);
18376            }
18377            buffer
18378                .diff_hunks_in_range(range.start..peek_end)
18379                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18380        })
18381    }
18382
18383    pub fn has_stageable_diff_hunks_in_ranges(
18384        &self,
18385        ranges: &[Range<Anchor>],
18386        snapshot: &MultiBufferSnapshot,
18387    ) -> bool {
18388        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18389        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18390    }
18391
18392    pub fn toggle_staged_selected_diff_hunks(
18393        &mut self,
18394        _: &::git::ToggleStaged,
18395        _: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) {
18398        let snapshot = self.buffer.read(cx).snapshot(cx);
18399        let ranges: Vec<_> = self
18400            .selections
18401            .disjoint_anchors()
18402            .iter()
18403            .map(|s| s.range())
18404            .collect();
18405        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18406        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18407    }
18408
18409    pub fn set_render_diff_hunk_controls(
18410        &mut self,
18411        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18412        cx: &mut Context<Self>,
18413    ) {
18414        self.render_diff_hunk_controls = render_diff_hunk_controls;
18415        cx.notify();
18416    }
18417
18418    pub fn stage_and_next(
18419        &mut self,
18420        _: &::git::StageAndNext,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) {
18424        self.do_stage_or_unstage_and_next(true, window, cx);
18425    }
18426
18427    pub fn unstage_and_next(
18428        &mut self,
18429        _: &::git::UnstageAndNext,
18430        window: &mut Window,
18431        cx: &mut Context<Self>,
18432    ) {
18433        self.do_stage_or_unstage_and_next(false, window, cx);
18434    }
18435
18436    pub fn stage_or_unstage_diff_hunks(
18437        &mut self,
18438        stage: bool,
18439        ranges: Vec<Range<Anchor>>,
18440        cx: &mut Context<Self>,
18441    ) {
18442        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18443        cx.spawn(async move |this, cx| {
18444            task.await?;
18445            this.update(cx, |this, cx| {
18446                let snapshot = this.buffer.read(cx).snapshot(cx);
18447                let chunk_by = this
18448                    .diff_hunks_in_ranges(&ranges, &snapshot)
18449                    .chunk_by(|hunk| hunk.buffer_id);
18450                for (buffer_id, hunks) in &chunk_by {
18451                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18452                }
18453            })
18454        })
18455        .detach_and_log_err(cx);
18456    }
18457
18458    fn save_buffers_for_ranges_if_needed(
18459        &mut self,
18460        ranges: &[Range<Anchor>],
18461        cx: &mut Context<Editor>,
18462    ) -> Task<Result<()>> {
18463        let multibuffer = self.buffer.read(cx);
18464        let snapshot = multibuffer.read(cx);
18465        let buffer_ids: HashSet<_> = ranges
18466            .iter()
18467            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18468            .collect();
18469        drop(snapshot);
18470
18471        let mut buffers = HashSet::default();
18472        for buffer_id in buffer_ids {
18473            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18474                let buffer = buffer_entity.read(cx);
18475                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18476                {
18477                    buffers.insert(buffer_entity);
18478                }
18479            }
18480        }
18481
18482        if let Some(project) = &self.project {
18483            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18484        } else {
18485            Task::ready(Ok(()))
18486        }
18487    }
18488
18489    fn do_stage_or_unstage_and_next(
18490        &mut self,
18491        stage: bool,
18492        window: &mut Window,
18493        cx: &mut Context<Self>,
18494    ) {
18495        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18496
18497        if ranges.iter().any(|range| range.start != range.end) {
18498            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18499            return;
18500        }
18501
18502        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18503        let snapshot = self.snapshot(window, cx);
18504        let position = self.selections.newest::<Point>(cx).head();
18505        let mut row = snapshot
18506            .buffer_snapshot
18507            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18508            .find(|hunk| hunk.row_range.start.0 > position.row)
18509            .map(|hunk| hunk.row_range.start);
18510
18511        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18512        // Outside of the project diff editor, wrap around to the beginning.
18513        if !all_diff_hunks_expanded {
18514            row = row.or_else(|| {
18515                snapshot
18516                    .buffer_snapshot
18517                    .diff_hunks_in_range(Point::zero()..position)
18518                    .find(|hunk| hunk.row_range.end.0 < position.row)
18519                    .map(|hunk| hunk.row_range.start)
18520            });
18521        }
18522
18523        if let Some(row) = row {
18524            let destination = Point::new(row.0, 0);
18525            let autoscroll = Autoscroll::center();
18526
18527            self.unfold_ranges(&[destination..destination], false, false, cx);
18528            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18529                s.select_ranges([destination..destination]);
18530            });
18531        }
18532    }
18533
18534    fn do_stage_or_unstage(
18535        &self,
18536        stage: bool,
18537        buffer_id: BufferId,
18538        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18539        cx: &mut App,
18540    ) -> Option<()> {
18541        let project = self.project()?;
18542        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18543        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18544        let buffer_snapshot = buffer.read(cx).snapshot();
18545        let file_exists = buffer_snapshot
18546            .file()
18547            .is_some_and(|file| file.disk_state().exists());
18548        diff.update(cx, |diff, cx| {
18549            diff.stage_or_unstage_hunks(
18550                stage,
18551                &hunks
18552                    .map(|hunk| buffer_diff::DiffHunk {
18553                        buffer_range: hunk.buffer_range,
18554                        diff_base_byte_range: hunk.diff_base_byte_range,
18555                        secondary_status: hunk.secondary_status,
18556                        range: Point::zero()..Point::zero(), // unused
18557                    })
18558                    .collect::<Vec<_>>(),
18559                &buffer_snapshot,
18560                file_exists,
18561                cx,
18562            )
18563        });
18564        None
18565    }
18566
18567    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18568        let ranges: Vec<_> = self
18569            .selections
18570            .disjoint_anchors()
18571            .iter()
18572            .map(|s| s.range())
18573            .collect();
18574        self.buffer
18575            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18576    }
18577
18578    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18579        self.buffer.update(cx, |buffer, cx| {
18580            let ranges = vec![Anchor::min()..Anchor::max()];
18581            if !buffer.all_diff_hunks_expanded()
18582                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18583            {
18584                buffer.collapse_diff_hunks(ranges, cx);
18585                true
18586            } else {
18587                false
18588            }
18589        })
18590    }
18591
18592    fn toggle_diff_hunks_in_ranges(
18593        &mut self,
18594        ranges: Vec<Range<Anchor>>,
18595        cx: &mut Context<Editor>,
18596    ) {
18597        self.buffer.update(cx, |buffer, cx| {
18598            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18599            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18600        })
18601    }
18602
18603    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18604        self.buffer.update(cx, |buffer, cx| {
18605            let snapshot = buffer.snapshot(cx);
18606            let excerpt_id = range.end.excerpt_id;
18607            let point_range = range.to_point(&snapshot);
18608            let expand = !buffer.single_hunk_is_expanded(range, cx);
18609            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18610        })
18611    }
18612
18613    pub(crate) fn apply_all_diff_hunks(
18614        &mut self,
18615        _: &ApplyAllDiffHunks,
18616        window: &mut Window,
18617        cx: &mut Context<Self>,
18618    ) {
18619        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18620
18621        let buffers = self.buffer.read(cx).all_buffers();
18622        for branch_buffer in buffers {
18623            branch_buffer.update(cx, |branch_buffer, cx| {
18624                branch_buffer.merge_into_base(Vec::new(), cx);
18625            });
18626        }
18627
18628        if let Some(project) = self.project.clone() {
18629            self.save(
18630                SaveOptions {
18631                    format: true,
18632                    autosave: false,
18633                },
18634                project,
18635                window,
18636                cx,
18637            )
18638            .detach_and_log_err(cx);
18639        }
18640    }
18641
18642    pub(crate) fn apply_selected_diff_hunks(
18643        &mut self,
18644        _: &ApplyDiffHunk,
18645        window: &mut Window,
18646        cx: &mut Context<Self>,
18647    ) {
18648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18649        let snapshot = self.snapshot(window, cx);
18650        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18651        let mut ranges_by_buffer = HashMap::default();
18652        self.transact(window, cx, |editor, _window, cx| {
18653            for hunk in hunks {
18654                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18655                    ranges_by_buffer
18656                        .entry(buffer.clone())
18657                        .or_insert_with(Vec::new)
18658                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18659                }
18660            }
18661
18662            for (buffer, ranges) in ranges_by_buffer {
18663                buffer.update(cx, |buffer, cx| {
18664                    buffer.merge_into_base(ranges, cx);
18665                });
18666            }
18667        });
18668
18669        if let Some(project) = self.project.clone() {
18670            self.save(
18671                SaveOptions {
18672                    format: true,
18673                    autosave: false,
18674                },
18675                project,
18676                window,
18677                cx,
18678            )
18679            .detach_and_log_err(cx);
18680        }
18681    }
18682
18683    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18684        if hovered != self.gutter_hovered {
18685            self.gutter_hovered = hovered;
18686            cx.notify();
18687        }
18688    }
18689
18690    pub fn insert_blocks(
18691        &mut self,
18692        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18693        autoscroll: Option<Autoscroll>,
18694        cx: &mut Context<Self>,
18695    ) -> Vec<CustomBlockId> {
18696        let blocks = self
18697            .display_map
18698            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18699        if let Some(autoscroll) = autoscroll {
18700            self.request_autoscroll(autoscroll, cx);
18701        }
18702        cx.notify();
18703        blocks
18704    }
18705
18706    pub fn resize_blocks(
18707        &mut self,
18708        heights: HashMap<CustomBlockId, u32>,
18709        autoscroll: Option<Autoscroll>,
18710        cx: &mut Context<Self>,
18711    ) {
18712        self.display_map
18713            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18714        if let Some(autoscroll) = autoscroll {
18715            self.request_autoscroll(autoscroll, cx);
18716        }
18717        cx.notify();
18718    }
18719
18720    pub fn replace_blocks(
18721        &mut self,
18722        renderers: HashMap<CustomBlockId, RenderBlock>,
18723        autoscroll: Option<Autoscroll>,
18724        cx: &mut Context<Self>,
18725    ) {
18726        self.display_map
18727            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18728        if let Some(autoscroll) = autoscroll {
18729            self.request_autoscroll(autoscroll, cx);
18730        }
18731        cx.notify();
18732    }
18733
18734    pub fn remove_blocks(
18735        &mut self,
18736        block_ids: HashSet<CustomBlockId>,
18737        autoscroll: Option<Autoscroll>,
18738        cx: &mut Context<Self>,
18739    ) {
18740        self.display_map.update(cx, |display_map, cx| {
18741            display_map.remove_blocks(block_ids, cx)
18742        });
18743        if let Some(autoscroll) = autoscroll {
18744            self.request_autoscroll(autoscroll, cx);
18745        }
18746        cx.notify();
18747    }
18748
18749    pub fn row_for_block(
18750        &self,
18751        block_id: CustomBlockId,
18752        cx: &mut Context<Self>,
18753    ) -> Option<DisplayRow> {
18754        self.display_map
18755            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18756    }
18757
18758    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18759        self.focused_block = Some(focused_block);
18760    }
18761
18762    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18763        self.focused_block.take()
18764    }
18765
18766    pub fn insert_creases(
18767        &mut self,
18768        creases: impl IntoIterator<Item = Crease<Anchor>>,
18769        cx: &mut Context<Self>,
18770    ) -> Vec<CreaseId> {
18771        self.display_map
18772            .update(cx, |map, cx| map.insert_creases(creases, cx))
18773    }
18774
18775    pub fn remove_creases(
18776        &mut self,
18777        ids: impl IntoIterator<Item = CreaseId>,
18778        cx: &mut Context<Self>,
18779    ) -> Vec<(CreaseId, Range<Anchor>)> {
18780        self.display_map
18781            .update(cx, |map, cx| map.remove_creases(ids, cx))
18782    }
18783
18784    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18785        self.display_map
18786            .update(cx, |map, cx| map.snapshot(cx))
18787            .longest_row()
18788    }
18789
18790    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18791        self.display_map
18792            .update(cx, |map, cx| map.snapshot(cx))
18793            .max_point()
18794    }
18795
18796    pub fn text(&self, cx: &App) -> String {
18797        self.buffer.read(cx).read(cx).text()
18798    }
18799
18800    pub fn is_empty(&self, cx: &App) -> bool {
18801        self.buffer.read(cx).read(cx).is_empty()
18802    }
18803
18804    pub fn text_option(&self, cx: &App) -> Option<String> {
18805        let text = self.text(cx);
18806        let text = text.trim();
18807
18808        if text.is_empty() {
18809            return None;
18810        }
18811
18812        Some(text.to_string())
18813    }
18814
18815    pub fn set_text(
18816        &mut self,
18817        text: impl Into<Arc<str>>,
18818        window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.transact(window, cx, |this, _, cx| {
18822            this.buffer
18823                .read(cx)
18824                .as_singleton()
18825                .expect("you can only call set_text on editors for singleton buffers")
18826                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18827        });
18828    }
18829
18830    pub fn display_text(&self, cx: &mut App) -> String {
18831        self.display_map
18832            .update(cx, |map, cx| map.snapshot(cx))
18833            .text()
18834    }
18835
18836    fn create_minimap(
18837        &self,
18838        minimap_settings: MinimapSettings,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) -> Option<Entity<Self>> {
18842        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18843            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18844    }
18845
18846    fn initialize_new_minimap(
18847        &self,
18848        minimap_settings: MinimapSettings,
18849        window: &mut Window,
18850        cx: &mut Context<Self>,
18851    ) -> Entity<Self> {
18852        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18853
18854        let mut minimap = Editor::new_internal(
18855            EditorMode::Minimap {
18856                parent: cx.weak_entity(),
18857            },
18858            self.buffer.clone(),
18859            None,
18860            Some(self.display_map.clone()),
18861            window,
18862            cx,
18863        );
18864        minimap.scroll_manager.clone_state(&self.scroll_manager);
18865        minimap.set_text_style_refinement(TextStyleRefinement {
18866            font_size: Some(MINIMAP_FONT_SIZE),
18867            font_weight: Some(MINIMAP_FONT_WEIGHT),
18868            ..Default::default()
18869        });
18870        minimap.update_minimap_configuration(minimap_settings, cx);
18871        cx.new(|_| minimap)
18872    }
18873
18874    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18875        let current_line_highlight = minimap_settings
18876            .current_line_highlight
18877            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18878        self.set_current_line_highlight(Some(current_line_highlight));
18879    }
18880
18881    pub fn minimap(&self) -> Option<&Entity<Self>> {
18882        self.minimap
18883            .as_ref()
18884            .filter(|_| self.minimap_visibility.visible())
18885    }
18886
18887    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18888        let mut wrap_guides = smallvec![];
18889
18890        if self.show_wrap_guides == Some(false) {
18891            return wrap_guides;
18892        }
18893
18894        let settings = self.buffer.read(cx).language_settings(cx);
18895        if settings.show_wrap_guides {
18896            match self.soft_wrap_mode(cx) {
18897                SoftWrap::Column(soft_wrap) => {
18898                    wrap_guides.push((soft_wrap as usize, true));
18899                }
18900                SoftWrap::Bounded(soft_wrap) => {
18901                    wrap_guides.push((soft_wrap as usize, true));
18902                }
18903                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18904            }
18905            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18906        }
18907
18908        wrap_guides
18909    }
18910
18911    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18912        let settings = self.buffer.read(cx).language_settings(cx);
18913        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18914        match mode {
18915            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18916                SoftWrap::None
18917            }
18918            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18919            language_settings::SoftWrap::PreferredLineLength => {
18920                SoftWrap::Column(settings.preferred_line_length)
18921            }
18922            language_settings::SoftWrap::Bounded => {
18923                SoftWrap::Bounded(settings.preferred_line_length)
18924            }
18925        }
18926    }
18927
18928    pub fn set_soft_wrap_mode(
18929        &mut self,
18930        mode: language_settings::SoftWrap,
18931
18932        cx: &mut Context<Self>,
18933    ) {
18934        self.soft_wrap_mode_override = Some(mode);
18935        cx.notify();
18936    }
18937
18938    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18939        self.hard_wrap = hard_wrap;
18940        cx.notify();
18941    }
18942
18943    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18944        self.text_style_refinement = Some(style);
18945    }
18946
18947    /// called by the Element so we know what style we were most recently rendered with.
18948    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18949        // We intentionally do not inform the display map about the minimap style
18950        // so that wrapping is not recalculated and stays consistent for the editor
18951        // and its linked minimap.
18952        if !self.mode.is_minimap() {
18953            let font = style.text.font();
18954            let font_size = style.text.font_size.to_pixels(window.rem_size());
18955            let display_map = self
18956                .placeholder_display_map
18957                .as_ref()
18958                .filter(|_| self.is_empty(cx))
18959                .unwrap_or(&self.display_map);
18960
18961            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18962        }
18963        self.style = Some(style);
18964    }
18965
18966    pub fn style(&self) -> Option<&EditorStyle> {
18967        self.style.as_ref()
18968    }
18969
18970    // Called by the element. This method is not designed to be called outside of the editor
18971    // element's layout code because it does not notify when rewrapping is computed synchronously.
18972    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18973        if self.is_empty(cx) {
18974            self.placeholder_display_map
18975                .as_ref()
18976                .map_or(false, |display_map| {
18977                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18978                })
18979        } else {
18980            self.display_map
18981                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18982        }
18983    }
18984
18985    pub fn set_soft_wrap(&mut self) {
18986        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18987    }
18988
18989    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18990        if self.soft_wrap_mode_override.is_some() {
18991            self.soft_wrap_mode_override.take();
18992        } else {
18993            let soft_wrap = match self.soft_wrap_mode(cx) {
18994                SoftWrap::GitDiff => return,
18995                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18996                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18997                    language_settings::SoftWrap::None
18998                }
18999            };
19000            self.soft_wrap_mode_override = Some(soft_wrap);
19001        }
19002        cx.notify();
19003    }
19004
19005    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19006        let Some(workspace) = self.workspace() else {
19007            return;
19008        };
19009        let fs = workspace.read(cx).app_state().fs.clone();
19010        let current_show = TabBarSettings::get_global(cx).show;
19011        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
19012            setting.show = Some(!current_show);
19013        });
19014    }
19015
19016    pub fn toggle_indent_guides(
19017        &mut self,
19018        _: &ToggleIndentGuides,
19019        _: &mut Window,
19020        cx: &mut Context<Self>,
19021    ) {
19022        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19023            self.buffer
19024                .read(cx)
19025                .language_settings(cx)
19026                .indent_guides
19027                .enabled
19028        });
19029        self.show_indent_guides = Some(!currently_enabled);
19030        cx.notify();
19031    }
19032
19033    fn should_show_indent_guides(&self) -> Option<bool> {
19034        self.show_indent_guides
19035    }
19036
19037    pub fn toggle_line_numbers(
19038        &mut self,
19039        _: &ToggleLineNumbers,
19040        _: &mut Window,
19041        cx: &mut Context<Self>,
19042    ) {
19043        let mut editor_settings = EditorSettings::get_global(cx).clone();
19044        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19045        EditorSettings::override_global(editor_settings, cx);
19046    }
19047
19048    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19049        if let Some(show_line_numbers) = self.show_line_numbers {
19050            return show_line_numbers;
19051        }
19052        EditorSettings::get_global(cx).gutter.line_numbers
19053    }
19054
19055    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19056        self.use_relative_line_numbers
19057            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19058    }
19059
19060    pub fn toggle_relative_line_numbers(
19061        &mut self,
19062        _: &ToggleRelativeLineNumbers,
19063        _: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        let is_relative = self.should_use_relative_line_numbers(cx);
19067        self.set_relative_line_number(Some(!is_relative), cx)
19068    }
19069
19070    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19071        self.use_relative_line_numbers = is_relative;
19072        cx.notify();
19073    }
19074
19075    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19076        self.show_gutter = show_gutter;
19077        cx.notify();
19078    }
19079
19080    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19081        self.show_scrollbars = ScrollbarAxes {
19082            horizontal: show,
19083            vertical: show,
19084        };
19085        cx.notify();
19086    }
19087
19088    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19089        self.show_scrollbars.vertical = show;
19090        cx.notify();
19091    }
19092
19093    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19094        self.show_scrollbars.horizontal = show;
19095        cx.notify();
19096    }
19097
19098    pub fn set_minimap_visibility(
19099        &mut self,
19100        minimap_visibility: MinimapVisibility,
19101        window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        if self.minimap_visibility != minimap_visibility {
19105            if minimap_visibility.visible() && self.minimap.is_none() {
19106                let minimap_settings = EditorSettings::get_global(cx).minimap;
19107                self.minimap =
19108                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19109            }
19110            self.minimap_visibility = minimap_visibility;
19111            cx.notify();
19112        }
19113    }
19114
19115    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19116        self.set_show_scrollbars(false, cx);
19117        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19118    }
19119
19120    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19121        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19122    }
19123
19124    /// Normally the text in full mode and auto height editors is padded on the
19125    /// left side by roughly half a character width for improved hit testing.
19126    ///
19127    /// Use this method to disable this for cases where this is not wanted (e.g.
19128    /// if you want to align the editor text with some other text above or below)
19129    /// or if you want to add this padding to single-line editors.
19130    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19131        self.offset_content = offset_content;
19132        cx.notify();
19133    }
19134
19135    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19136        self.show_line_numbers = Some(show_line_numbers);
19137        cx.notify();
19138    }
19139
19140    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19141        self.disable_expand_excerpt_buttons = true;
19142        cx.notify();
19143    }
19144
19145    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19146        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19147        cx.notify();
19148    }
19149
19150    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19151        self.show_code_actions = Some(show_code_actions);
19152        cx.notify();
19153    }
19154
19155    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19156        self.show_runnables = Some(show_runnables);
19157        cx.notify();
19158    }
19159
19160    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19161        self.show_breakpoints = Some(show_breakpoints);
19162        cx.notify();
19163    }
19164
19165    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19166        if self.display_map.read(cx).masked != masked {
19167            self.display_map.update(cx, |map, _| map.masked = masked);
19168        }
19169        cx.notify()
19170    }
19171
19172    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19173        self.show_wrap_guides = Some(show_wrap_guides);
19174        cx.notify();
19175    }
19176
19177    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19178        self.show_indent_guides = Some(show_indent_guides);
19179        cx.notify();
19180    }
19181
19182    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19183        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19184            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19185                && let Some(dir) = file.abs_path(cx).parent()
19186            {
19187                return Some(dir.to_owned());
19188            }
19189
19190            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19191                return Some(project_path.path.to_path_buf());
19192            }
19193        }
19194
19195        None
19196    }
19197
19198    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19199        self.active_excerpt(cx)?
19200            .1
19201            .read(cx)
19202            .file()
19203            .and_then(|f| f.as_local())
19204    }
19205
19206    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19207        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19208            let buffer = buffer.read(cx);
19209            if let Some(project_path) = buffer.project_path(cx) {
19210                let project = self.project()?.read(cx);
19211                project.absolute_path(&project_path, cx)
19212            } else {
19213                buffer
19214                    .file()
19215                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19216            }
19217        })
19218    }
19219
19220    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19221        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19222            let project_path = buffer.read(cx).project_path(cx)?;
19223            let project = self.project()?.read(cx);
19224            let entry = project.entry_for_path(&project_path, cx)?;
19225            let path = entry.path.to_path_buf();
19226            Some(path)
19227        })
19228    }
19229
19230    pub fn reveal_in_finder(
19231        &mut self,
19232        _: &RevealInFileManager,
19233        _window: &mut Window,
19234        cx: &mut Context<Self>,
19235    ) {
19236        if let Some(target) = self.target_file(cx) {
19237            cx.reveal_path(&target.abs_path(cx));
19238        }
19239    }
19240
19241    pub fn copy_path(
19242        &mut self,
19243        _: &zed_actions::workspace::CopyPath,
19244        _window: &mut Window,
19245        cx: &mut Context<Self>,
19246    ) {
19247        if let Some(path) = self.target_file_abs_path(cx)
19248            && let Some(path) = path.to_str()
19249        {
19250            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19251        }
19252    }
19253
19254    pub fn copy_relative_path(
19255        &mut self,
19256        _: &zed_actions::workspace::CopyRelativePath,
19257        _window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        if let Some(path) = self.target_file_path(cx)
19261            && let Some(path) = path.to_str()
19262        {
19263            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19264        }
19265    }
19266
19267    /// Returns the project path for the editor's buffer, if any buffer is
19268    /// opened in the editor.
19269    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19270        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19271            buffer.read(cx).project_path(cx)
19272        } else {
19273            None
19274        }
19275    }
19276
19277    // Returns true if the editor handled a go-to-line request
19278    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19279        maybe!({
19280            let breakpoint_store = self.breakpoint_store.as_ref()?;
19281
19282            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19283            else {
19284                self.clear_row_highlights::<ActiveDebugLine>();
19285                return None;
19286            };
19287
19288            let position = active_stack_frame.position;
19289            let buffer_id = position.buffer_id?;
19290            let snapshot = self
19291                .project
19292                .as_ref()?
19293                .read(cx)
19294                .buffer_for_id(buffer_id, cx)?
19295                .read(cx)
19296                .snapshot();
19297
19298            let mut handled = false;
19299            for (id, ExcerptRange { context, .. }) in
19300                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19301            {
19302                if context.start.cmp(&position, &snapshot).is_ge()
19303                    || context.end.cmp(&position, &snapshot).is_lt()
19304                {
19305                    continue;
19306                }
19307                let snapshot = self.buffer.read(cx).snapshot(cx);
19308                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19309
19310                handled = true;
19311                self.clear_row_highlights::<ActiveDebugLine>();
19312
19313                self.go_to_line::<ActiveDebugLine>(
19314                    multibuffer_anchor,
19315                    Some(cx.theme().colors().editor_debugger_active_line_background),
19316                    window,
19317                    cx,
19318                );
19319
19320                cx.notify();
19321            }
19322
19323            handled.then_some(())
19324        })
19325        .is_some()
19326    }
19327
19328    pub fn copy_file_name_without_extension(
19329        &mut self,
19330        _: &CopyFileNameWithoutExtension,
19331        _: &mut Window,
19332        cx: &mut Context<Self>,
19333    ) {
19334        if let Some(file) = self.target_file(cx)
19335            && let Some(file_stem) = file.path().file_stem()
19336            && let Some(name) = file_stem.to_str()
19337        {
19338            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19339        }
19340    }
19341
19342    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19343        if let Some(file) = self.target_file(cx)
19344            && let Some(file_name) = file.path().file_name()
19345            && let Some(name) = file_name.to_str()
19346        {
19347            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19348        }
19349    }
19350
19351    pub fn toggle_git_blame(
19352        &mut self,
19353        _: &::git::Blame,
19354        window: &mut Window,
19355        cx: &mut Context<Self>,
19356    ) {
19357        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19358
19359        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19360            self.start_git_blame(true, window, cx);
19361        }
19362
19363        cx.notify();
19364    }
19365
19366    pub fn toggle_git_blame_inline(
19367        &mut self,
19368        _: &ToggleGitBlameInline,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) {
19372        self.toggle_git_blame_inline_internal(true, window, cx);
19373        cx.notify();
19374    }
19375
19376    pub fn open_git_blame_commit(
19377        &mut self,
19378        _: &OpenGitBlameCommit,
19379        window: &mut Window,
19380        cx: &mut Context<Self>,
19381    ) {
19382        self.open_git_blame_commit_internal(window, cx);
19383    }
19384
19385    fn open_git_blame_commit_internal(
19386        &mut self,
19387        window: &mut Window,
19388        cx: &mut Context<Self>,
19389    ) -> Option<()> {
19390        let blame = self.blame.as_ref()?;
19391        let snapshot = self.snapshot(window, cx);
19392        let cursor = self.selections.newest::<Point>(cx).head();
19393        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19394        let (_, blame_entry) = blame
19395            .update(cx, |blame, cx| {
19396                blame
19397                    .blame_for_rows(
19398                        &[RowInfo {
19399                            buffer_id: Some(buffer.remote_id()),
19400                            buffer_row: Some(point.row),
19401                            ..Default::default()
19402                        }],
19403                        cx,
19404                    )
19405                    .next()
19406            })
19407            .flatten()?;
19408        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19409        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19410        let workspace = self.workspace()?.downgrade();
19411        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19412        None
19413    }
19414
19415    pub fn git_blame_inline_enabled(&self) -> bool {
19416        self.git_blame_inline_enabled
19417    }
19418
19419    pub fn toggle_selection_menu(
19420        &mut self,
19421        _: &ToggleSelectionMenu,
19422        _: &mut Window,
19423        cx: &mut Context<Self>,
19424    ) {
19425        self.show_selection_menu = self
19426            .show_selection_menu
19427            .map(|show_selections_menu| !show_selections_menu)
19428            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19429
19430        cx.notify();
19431    }
19432
19433    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19434        self.show_selection_menu
19435            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19436    }
19437
19438    fn start_git_blame(
19439        &mut self,
19440        user_triggered: bool,
19441        window: &mut Window,
19442        cx: &mut Context<Self>,
19443    ) {
19444        if let Some(project) = self.project() {
19445            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19446                && buffer.read(cx).file().is_none()
19447            {
19448                return;
19449            }
19450
19451            let focused = self.focus_handle(cx).contains_focused(window, cx);
19452
19453            let project = project.clone();
19454            let blame = cx
19455                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19456            self.blame_subscription =
19457                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19458            self.blame = Some(blame);
19459        }
19460    }
19461
19462    fn toggle_git_blame_inline_internal(
19463        &mut self,
19464        user_triggered: bool,
19465        window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        if self.git_blame_inline_enabled {
19469            self.git_blame_inline_enabled = false;
19470            self.show_git_blame_inline = false;
19471            self.show_git_blame_inline_delay_task.take();
19472        } else {
19473            self.git_blame_inline_enabled = true;
19474            self.start_git_blame_inline(user_triggered, window, cx);
19475        }
19476
19477        cx.notify();
19478    }
19479
19480    fn start_git_blame_inline(
19481        &mut self,
19482        user_triggered: bool,
19483        window: &mut Window,
19484        cx: &mut Context<Self>,
19485    ) {
19486        self.start_git_blame(user_triggered, window, cx);
19487
19488        if ProjectSettings::get_global(cx)
19489            .git
19490            .inline_blame_delay()
19491            .is_some()
19492        {
19493            self.start_inline_blame_timer(window, cx);
19494        } else {
19495            self.show_git_blame_inline = true
19496        }
19497    }
19498
19499    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19500        self.blame.as_ref()
19501    }
19502
19503    pub fn show_git_blame_gutter(&self) -> bool {
19504        self.show_git_blame_gutter
19505    }
19506
19507    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19508        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19509    }
19510
19511    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19512        self.show_git_blame_inline
19513            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19514            && !self.newest_selection_head_on_empty_line(cx)
19515            && self.has_blame_entries(cx)
19516    }
19517
19518    fn has_blame_entries(&self, cx: &App) -> bool {
19519        self.blame()
19520            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19521    }
19522
19523    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19524        let cursor_anchor = self.selections.newest_anchor().head();
19525
19526        let snapshot = self.buffer.read(cx).snapshot(cx);
19527        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19528
19529        snapshot.line_len(buffer_row) == 0
19530    }
19531
19532    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19533        let buffer_and_selection = maybe!({
19534            let selection = self.selections.newest::<Point>(cx);
19535            let selection_range = selection.range();
19536
19537            let multi_buffer = self.buffer().read(cx);
19538            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19539            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19540
19541            let (buffer, range, _) = if selection.reversed {
19542                buffer_ranges.first()
19543            } else {
19544                buffer_ranges.last()
19545            }?;
19546
19547            let selection = text::ToPoint::to_point(&range.start, buffer).row
19548                ..text::ToPoint::to_point(&range.end, buffer).row;
19549            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19550        });
19551
19552        let Some((buffer, selection)) = buffer_and_selection else {
19553            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19554        };
19555
19556        let Some(project) = self.project() else {
19557            return Task::ready(Err(anyhow!("editor does not have project")));
19558        };
19559
19560        project.update(cx, |project, cx| {
19561            project.get_permalink_to_line(&buffer, selection, cx)
19562        })
19563    }
19564
19565    pub fn copy_permalink_to_line(
19566        &mut self,
19567        _: &CopyPermalinkToLine,
19568        window: &mut Window,
19569        cx: &mut Context<Self>,
19570    ) {
19571        let permalink_task = self.get_permalink_to_line(cx);
19572        let workspace = self.workspace();
19573
19574        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19575            Ok(permalink) => {
19576                cx.update(|_, cx| {
19577                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19578                })
19579                .ok();
19580            }
19581            Err(err) => {
19582                let message = format!("Failed to copy permalink: {err}");
19583
19584                anyhow::Result::<()>::Err(err).log_err();
19585
19586                if let Some(workspace) = workspace {
19587                    workspace
19588                        .update_in(cx, |workspace, _, cx| {
19589                            struct CopyPermalinkToLine;
19590
19591                            workspace.show_toast(
19592                                Toast::new(
19593                                    NotificationId::unique::<CopyPermalinkToLine>(),
19594                                    message,
19595                                ),
19596                                cx,
19597                            )
19598                        })
19599                        .ok();
19600                }
19601            }
19602        })
19603        .detach();
19604    }
19605
19606    pub fn copy_file_location(
19607        &mut self,
19608        _: &CopyFileLocation,
19609        _: &mut Window,
19610        cx: &mut Context<Self>,
19611    ) {
19612        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19613        if let Some(file) = self.target_file(cx)
19614            && let Some(path) = file.path().to_str()
19615        {
19616            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19617        }
19618    }
19619
19620    pub fn open_permalink_to_line(
19621        &mut self,
19622        _: &OpenPermalinkToLine,
19623        window: &mut Window,
19624        cx: &mut Context<Self>,
19625    ) {
19626        let permalink_task = self.get_permalink_to_line(cx);
19627        let workspace = self.workspace();
19628
19629        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19630            Ok(permalink) => {
19631                cx.update(|_, cx| {
19632                    cx.open_url(permalink.as_ref());
19633                })
19634                .ok();
19635            }
19636            Err(err) => {
19637                let message = format!("Failed to open permalink: {err}");
19638
19639                anyhow::Result::<()>::Err(err).log_err();
19640
19641                if let Some(workspace) = workspace {
19642                    workspace
19643                        .update(cx, |workspace, cx| {
19644                            struct OpenPermalinkToLine;
19645
19646                            workspace.show_toast(
19647                                Toast::new(
19648                                    NotificationId::unique::<OpenPermalinkToLine>(),
19649                                    message,
19650                                ),
19651                                cx,
19652                            )
19653                        })
19654                        .ok();
19655                }
19656            }
19657        })
19658        .detach();
19659    }
19660
19661    pub fn insert_uuid_v4(
19662        &mut self,
19663        _: &InsertUuidV4,
19664        window: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        self.insert_uuid(UuidVersion::V4, window, cx);
19668    }
19669
19670    pub fn insert_uuid_v7(
19671        &mut self,
19672        _: &InsertUuidV7,
19673        window: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        self.insert_uuid(UuidVersion::V7, window, cx);
19677    }
19678
19679    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19681        self.transact(window, cx, |this, window, cx| {
19682            let edits = this
19683                .selections
19684                .all::<Point>(cx)
19685                .into_iter()
19686                .map(|selection| {
19687                    let uuid = match version {
19688                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19689                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19690                    };
19691
19692                    (selection.range(), uuid.to_string())
19693                });
19694            this.edit(edits, cx);
19695            this.refresh_edit_prediction(true, false, window, cx);
19696        });
19697    }
19698
19699    pub fn open_selections_in_multibuffer(
19700        &mut self,
19701        _: &OpenSelectionsInMultibuffer,
19702        window: &mut Window,
19703        cx: &mut Context<Self>,
19704    ) {
19705        let multibuffer = self.buffer.read(cx);
19706
19707        let Some(buffer) = multibuffer.as_singleton() else {
19708            return;
19709        };
19710
19711        let Some(workspace) = self.workspace() else {
19712            return;
19713        };
19714
19715        let title = multibuffer.title(cx).to_string();
19716
19717        let locations = self
19718            .selections
19719            .all_anchors(cx)
19720            .iter()
19721            .map(|selection| Location {
19722                buffer: buffer.clone(),
19723                range: selection.start.text_anchor..selection.end.text_anchor,
19724            })
19725            .collect::<Vec<_>>();
19726
19727        cx.spawn_in(window, async move |_, cx| {
19728            workspace.update_in(cx, |workspace, window, cx| {
19729                Self::open_locations_in_multibuffer(
19730                    workspace,
19731                    locations,
19732                    format!("Selections for '{title}'"),
19733                    false,
19734                    MultibufferSelectionMode::All,
19735                    window,
19736                    cx,
19737                );
19738            })
19739        })
19740        .detach();
19741    }
19742
19743    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19744    /// last highlight added will be used.
19745    ///
19746    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19747    pub fn highlight_rows<T: 'static>(
19748        &mut self,
19749        range: Range<Anchor>,
19750        color: Hsla,
19751        options: RowHighlightOptions,
19752        cx: &mut Context<Self>,
19753    ) {
19754        let snapshot = self.buffer().read(cx).snapshot(cx);
19755        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19756        let ix = row_highlights.binary_search_by(|highlight| {
19757            Ordering::Equal
19758                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19759                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19760        });
19761
19762        if let Err(mut ix) = ix {
19763            let index = post_inc(&mut self.highlight_order);
19764
19765            // If this range intersects with the preceding highlight, then merge it with
19766            // the preceding highlight. Otherwise insert a new highlight.
19767            let mut merged = false;
19768            if ix > 0 {
19769                let prev_highlight = &mut row_highlights[ix - 1];
19770                if prev_highlight
19771                    .range
19772                    .end
19773                    .cmp(&range.start, &snapshot)
19774                    .is_ge()
19775                {
19776                    ix -= 1;
19777                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19778                        prev_highlight.range.end = range.end;
19779                    }
19780                    merged = true;
19781                    prev_highlight.index = index;
19782                    prev_highlight.color = color;
19783                    prev_highlight.options = options;
19784                }
19785            }
19786
19787            if !merged {
19788                row_highlights.insert(
19789                    ix,
19790                    RowHighlight {
19791                        range,
19792                        index,
19793                        color,
19794                        options,
19795                        type_id: TypeId::of::<T>(),
19796                    },
19797                );
19798            }
19799
19800            // If any of the following highlights intersect with this one, merge them.
19801            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19802                let highlight = &row_highlights[ix];
19803                if next_highlight
19804                    .range
19805                    .start
19806                    .cmp(&highlight.range.end, &snapshot)
19807                    .is_le()
19808                {
19809                    if next_highlight
19810                        .range
19811                        .end
19812                        .cmp(&highlight.range.end, &snapshot)
19813                        .is_gt()
19814                    {
19815                        row_highlights[ix].range.end = next_highlight.range.end;
19816                    }
19817                    row_highlights.remove(ix + 1);
19818                } else {
19819                    break;
19820                }
19821            }
19822        }
19823    }
19824
19825    /// Remove any highlighted row ranges of the given type that intersect the
19826    /// given ranges.
19827    pub fn remove_highlighted_rows<T: 'static>(
19828        &mut self,
19829        ranges_to_remove: Vec<Range<Anchor>>,
19830        cx: &mut Context<Self>,
19831    ) {
19832        let snapshot = self.buffer().read(cx).snapshot(cx);
19833        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19834        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19835        row_highlights.retain(|highlight| {
19836            while let Some(range_to_remove) = ranges_to_remove.peek() {
19837                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19838                    Ordering::Less | Ordering::Equal => {
19839                        ranges_to_remove.next();
19840                    }
19841                    Ordering::Greater => {
19842                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19843                            Ordering::Less | Ordering::Equal => {
19844                                return false;
19845                            }
19846                            Ordering::Greater => break,
19847                        }
19848                    }
19849                }
19850            }
19851
19852            true
19853        })
19854    }
19855
19856    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19857    pub fn clear_row_highlights<T: 'static>(&mut self) {
19858        self.highlighted_rows.remove(&TypeId::of::<T>());
19859    }
19860
19861    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19862    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19863        self.highlighted_rows
19864            .get(&TypeId::of::<T>())
19865            .map_or(&[] as &[_], |vec| vec.as_slice())
19866            .iter()
19867            .map(|highlight| (highlight.range.clone(), highlight.color))
19868    }
19869
19870    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19871    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19872    /// Allows to ignore certain kinds of highlights.
19873    pub fn highlighted_display_rows(
19874        &self,
19875        window: &mut Window,
19876        cx: &mut App,
19877    ) -> BTreeMap<DisplayRow, LineHighlight> {
19878        let snapshot = self.snapshot(window, cx);
19879        let mut used_highlight_orders = HashMap::default();
19880        self.highlighted_rows
19881            .iter()
19882            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19883            .fold(
19884                BTreeMap::<DisplayRow, LineHighlight>::new(),
19885                |mut unique_rows, highlight| {
19886                    let start = highlight.range.start.to_display_point(&snapshot);
19887                    let end = highlight.range.end.to_display_point(&snapshot);
19888                    let start_row = start.row().0;
19889                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19890                        && end.column() == 0
19891                    {
19892                        end.row().0.saturating_sub(1)
19893                    } else {
19894                        end.row().0
19895                    };
19896                    for row in start_row..=end_row {
19897                        let used_index =
19898                            used_highlight_orders.entry(row).or_insert(highlight.index);
19899                        if highlight.index >= *used_index {
19900                            *used_index = highlight.index;
19901                            unique_rows.insert(
19902                                DisplayRow(row),
19903                                LineHighlight {
19904                                    include_gutter: highlight.options.include_gutter,
19905                                    border: None,
19906                                    background: highlight.color.into(),
19907                                    type_id: Some(highlight.type_id),
19908                                },
19909                            );
19910                        }
19911                    }
19912                    unique_rows
19913                },
19914            )
19915    }
19916
19917    pub fn highlighted_display_row_for_autoscroll(
19918        &self,
19919        snapshot: &DisplaySnapshot,
19920    ) -> Option<DisplayRow> {
19921        self.highlighted_rows
19922            .values()
19923            .flat_map(|highlighted_rows| highlighted_rows.iter())
19924            .filter_map(|highlight| {
19925                if highlight.options.autoscroll {
19926                    Some(highlight.range.start.to_display_point(snapshot).row())
19927                } else {
19928                    None
19929                }
19930            })
19931            .min()
19932    }
19933
19934    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19935        self.highlight_background::<SearchWithinRange>(
19936            ranges,
19937            |colors| colors.colors().editor_document_highlight_read_background,
19938            cx,
19939        )
19940    }
19941
19942    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19943        self.breadcrumb_header = Some(new_header);
19944    }
19945
19946    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19947        self.clear_background_highlights::<SearchWithinRange>(cx);
19948    }
19949
19950    pub fn highlight_background<T: 'static>(
19951        &mut self,
19952        ranges: &[Range<Anchor>],
19953        color_fetcher: fn(&Theme) -> Hsla,
19954        cx: &mut Context<Self>,
19955    ) {
19956        self.background_highlights.insert(
19957            HighlightKey::Type(TypeId::of::<T>()),
19958            (color_fetcher, Arc::from(ranges)),
19959        );
19960        self.scrollbar_marker_state.dirty = true;
19961        cx.notify();
19962    }
19963
19964    pub fn highlight_background_key<T: 'static>(
19965        &mut self,
19966        key: usize,
19967        ranges: &[Range<Anchor>],
19968        color_fetcher: fn(&Theme) -> Hsla,
19969        cx: &mut Context<Self>,
19970    ) {
19971        self.background_highlights.insert(
19972            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19973            (color_fetcher, Arc::from(ranges)),
19974        );
19975        self.scrollbar_marker_state.dirty = true;
19976        cx.notify();
19977    }
19978
19979    pub fn clear_background_highlights<T: 'static>(
19980        &mut self,
19981        cx: &mut Context<Self>,
19982    ) -> Option<BackgroundHighlight> {
19983        let text_highlights = self
19984            .background_highlights
19985            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19986        if !text_highlights.1.is_empty() {
19987            self.scrollbar_marker_state.dirty = true;
19988            cx.notify();
19989        }
19990        Some(text_highlights)
19991    }
19992
19993    pub fn highlight_gutter<T: 'static>(
19994        &mut self,
19995        ranges: impl Into<Vec<Range<Anchor>>>,
19996        color_fetcher: fn(&App) -> Hsla,
19997        cx: &mut Context<Self>,
19998    ) {
19999        self.gutter_highlights
20000            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20001        cx.notify();
20002    }
20003
20004    pub fn clear_gutter_highlights<T: 'static>(
20005        &mut self,
20006        cx: &mut Context<Self>,
20007    ) -> Option<GutterHighlight> {
20008        cx.notify();
20009        self.gutter_highlights.remove(&TypeId::of::<T>())
20010    }
20011
20012    pub fn insert_gutter_highlight<T: 'static>(
20013        &mut self,
20014        range: Range<Anchor>,
20015        color_fetcher: fn(&App) -> Hsla,
20016        cx: &mut Context<Self>,
20017    ) {
20018        let snapshot = self.buffer().read(cx).snapshot(cx);
20019        let mut highlights = self
20020            .gutter_highlights
20021            .remove(&TypeId::of::<T>())
20022            .map(|(_, highlights)| highlights)
20023            .unwrap_or_default();
20024        let ix = highlights.binary_search_by(|highlight| {
20025            Ordering::Equal
20026                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20027                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20028        });
20029        if let Err(ix) = ix {
20030            highlights.insert(ix, range);
20031        }
20032        self.gutter_highlights
20033            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20034    }
20035
20036    pub fn remove_gutter_highlights<T: 'static>(
20037        &mut self,
20038        ranges_to_remove: Vec<Range<Anchor>>,
20039        cx: &mut Context<Self>,
20040    ) {
20041        let snapshot = self.buffer().read(cx).snapshot(cx);
20042        let Some((color_fetcher, mut gutter_highlights)) =
20043            self.gutter_highlights.remove(&TypeId::of::<T>())
20044        else {
20045            return;
20046        };
20047        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20048        gutter_highlights.retain(|highlight| {
20049            while let Some(range_to_remove) = ranges_to_remove.peek() {
20050                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20051                    Ordering::Less | Ordering::Equal => {
20052                        ranges_to_remove.next();
20053                    }
20054                    Ordering::Greater => {
20055                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20056                            Ordering::Less | Ordering::Equal => {
20057                                return false;
20058                            }
20059                            Ordering::Greater => break,
20060                        }
20061                    }
20062                }
20063            }
20064
20065            true
20066        });
20067        self.gutter_highlights
20068            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20069    }
20070
20071    #[cfg(feature = "test-support")]
20072    pub fn all_text_highlights(
20073        &self,
20074        window: &mut Window,
20075        cx: &mut Context<Self>,
20076    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20077        let snapshot = self.snapshot(window, cx);
20078        self.display_map.update(cx, |display_map, _| {
20079            display_map
20080                .all_text_highlights()
20081                .map(|highlight| {
20082                    let (style, ranges) = highlight.as_ref();
20083                    (
20084                        *style,
20085                        ranges
20086                            .iter()
20087                            .map(|range| range.clone().to_display_points(&snapshot))
20088                            .collect(),
20089                    )
20090                })
20091                .collect()
20092        })
20093    }
20094
20095    #[cfg(feature = "test-support")]
20096    pub fn all_text_background_highlights(
20097        &self,
20098        window: &mut Window,
20099        cx: &mut Context<Self>,
20100    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20101        let snapshot = self.snapshot(window, cx);
20102        let buffer = &snapshot.buffer_snapshot;
20103        let start = buffer.anchor_before(0);
20104        let end = buffer.anchor_after(buffer.len());
20105        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20106    }
20107
20108    #[cfg(any(test, feature = "test-support"))]
20109    pub fn sorted_background_highlights_in_range(
20110        &self,
20111        search_range: Range<Anchor>,
20112        display_snapshot: &DisplaySnapshot,
20113        theme: &Theme,
20114    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20115        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20116        res.sort_by(|a, b| {
20117            a.0.start
20118                .cmp(&b.0.start)
20119                .then_with(|| a.0.end.cmp(&b.0.end))
20120                .then_with(|| a.1.cmp(&b.1))
20121        });
20122        res
20123    }
20124
20125    #[cfg(feature = "test-support")]
20126    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20127        let snapshot = self.buffer().read(cx).snapshot(cx);
20128
20129        let highlights = self
20130            .background_highlights
20131            .get(&HighlightKey::Type(TypeId::of::<
20132                items::BufferSearchHighlights,
20133            >()));
20134
20135        if let Some((_color, ranges)) = highlights {
20136            ranges
20137                .iter()
20138                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20139                .collect_vec()
20140        } else {
20141            vec![]
20142        }
20143    }
20144
20145    fn document_highlights_for_position<'a>(
20146        &'a self,
20147        position: Anchor,
20148        buffer: &'a MultiBufferSnapshot,
20149    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20150        let read_highlights = self
20151            .background_highlights
20152            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20153            .map(|h| &h.1);
20154        let write_highlights = self
20155            .background_highlights
20156            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20157            .map(|h| &h.1);
20158        let left_position = position.bias_left(buffer);
20159        let right_position = position.bias_right(buffer);
20160        read_highlights
20161            .into_iter()
20162            .chain(write_highlights)
20163            .flat_map(move |ranges| {
20164                let start_ix = match ranges.binary_search_by(|probe| {
20165                    let cmp = probe.end.cmp(&left_position, buffer);
20166                    if cmp.is_ge() {
20167                        Ordering::Greater
20168                    } else {
20169                        Ordering::Less
20170                    }
20171                }) {
20172                    Ok(i) | Err(i) => i,
20173                };
20174
20175                ranges[start_ix..]
20176                    .iter()
20177                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20178            })
20179    }
20180
20181    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20182        self.background_highlights
20183            .get(&HighlightKey::Type(TypeId::of::<T>()))
20184            .is_some_and(|(_, highlights)| !highlights.is_empty())
20185    }
20186
20187    /// Returns all background highlights for a given range.
20188    ///
20189    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20190    pub fn background_highlights_in_range(
20191        &self,
20192        search_range: Range<Anchor>,
20193        display_snapshot: &DisplaySnapshot,
20194        theme: &Theme,
20195    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20196        let mut results = Vec::new();
20197        for (color_fetcher, ranges) in self.background_highlights.values() {
20198            let color = color_fetcher(theme);
20199            let start_ix = match ranges.binary_search_by(|probe| {
20200                let cmp = probe
20201                    .end
20202                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20203                if cmp.is_gt() {
20204                    Ordering::Greater
20205                } else {
20206                    Ordering::Less
20207                }
20208            }) {
20209                Ok(i) | Err(i) => i,
20210            };
20211            for range in &ranges[start_ix..] {
20212                if range
20213                    .start
20214                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20215                    .is_ge()
20216                {
20217                    break;
20218                }
20219
20220                let start = range.start.to_display_point(display_snapshot);
20221                let end = range.end.to_display_point(display_snapshot);
20222                results.push((start..end, color))
20223            }
20224        }
20225        results
20226    }
20227
20228    pub fn gutter_highlights_in_range(
20229        &self,
20230        search_range: Range<Anchor>,
20231        display_snapshot: &DisplaySnapshot,
20232        cx: &App,
20233    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20234        let mut results = Vec::new();
20235        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20236            let color = color_fetcher(cx);
20237            let start_ix = match ranges.binary_search_by(|probe| {
20238                let cmp = probe
20239                    .end
20240                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20241                if cmp.is_gt() {
20242                    Ordering::Greater
20243                } else {
20244                    Ordering::Less
20245                }
20246            }) {
20247                Ok(i) | Err(i) => i,
20248            };
20249            for range in &ranges[start_ix..] {
20250                if range
20251                    .start
20252                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20253                    .is_ge()
20254                {
20255                    break;
20256                }
20257
20258                let start = range.start.to_display_point(display_snapshot);
20259                let end = range.end.to_display_point(display_snapshot);
20260                results.push((start..end, color))
20261            }
20262        }
20263        results
20264    }
20265
20266    /// Get the text ranges corresponding to the redaction query
20267    pub fn redacted_ranges(
20268        &self,
20269        search_range: Range<Anchor>,
20270        display_snapshot: &DisplaySnapshot,
20271        cx: &App,
20272    ) -> Vec<Range<DisplayPoint>> {
20273        display_snapshot
20274            .buffer_snapshot
20275            .redacted_ranges(search_range, |file| {
20276                if let Some(file) = file {
20277                    file.is_private()
20278                        && EditorSettings::get(
20279                            Some(SettingsLocation {
20280                                worktree_id: file.worktree_id(cx),
20281                                path: file.path().as_ref(),
20282                            }),
20283                            cx,
20284                        )
20285                        .redact_private_values
20286                } else {
20287                    false
20288                }
20289            })
20290            .map(|range| {
20291                range.start.to_display_point(display_snapshot)
20292                    ..range.end.to_display_point(display_snapshot)
20293            })
20294            .collect()
20295    }
20296
20297    pub fn highlight_text_key<T: 'static>(
20298        &mut self,
20299        key: usize,
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(
20306                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20307                ranges,
20308                style,
20309            );
20310        });
20311        cx.notify();
20312    }
20313
20314    pub fn highlight_text<T: 'static>(
20315        &mut self,
20316        ranges: Vec<Range<Anchor>>,
20317        style: HighlightStyle,
20318        cx: &mut Context<Self>,
20319    ) {
20320        self.display_map.update(cx, |map, _| {
20321            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20322        });
20323        cx.notify();
20324    }
20325
20326    pub(crate) fn highlight_inlays<T: 'static>(
20327        &mut self,
20328        highlights: Vec<InlayHighlight>,
20329        style: HighlightStyle,
20330        cx: &mut Context<Self>,
20331    ) {
20332        self.display_map.update(cx, |map, _| {
20333            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20334        });
20335        cx.notify();
20336    }
20337
20338    pub fn text_highlights<'a, T: 'static>(
20339        &'a self,
20340        cx: &'a App,
20341    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20342        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20343    }
20344
20345    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20346        let cleared = self
20347            .display_map
20348            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20349        if cleared {
20350            cx.notify();
20351        }
20352    }
20353
20354    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20355        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20356            && self.focus_handle.is_focused(window)
20357    }
20358
20359    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20360        self.show_cursor_when_unfocused = is_enabled;
20361        cx.notify();
20362    }
20363
20364    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20365        cx.notify();
20366    }
20367
20368    fn on_debug_session_event(
20369        &mut self,
20370        _session: Entity<Session>,
20371        event: &SessionEvent,
20372        cx: &mut Context<Self>,
20373    ) {
20374        if let SessionEvent::InvalidateInlineValue = event {
20375            self.refresh_inline_values(cx);
20376        }
20377    }
20378
20379    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20380        let Some(project) = self.project.clone() else {
20381            return;
20382        };
20383
20384        if !self.inline_value_cache.enabled {
20385            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20386            self.splice_inlays(&inlays, Vec::new(), cx);
20387            return;
20388        }
20389
20390        let current_execution_position = self
20391            .highlighted_rows
20392            .get(&TypeId::of::<ActiveDebugLine>())
20393            .and_then(|lines| lines.last().map(|line| line.range.end));
20394
20395        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20396            let inline_values = editor
20397                .update(cx, |editor, cx| {
20398                    let Some(current_execution_position) = current_execution_position else {
20399                        return Some(Task::ready(Ok(Vec::new())));
20400                    };
20401
20402                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20403                        let snapshot = buffer.snapshot(cx);
20404
20405                        let excerpt = snapshot.excerpt_containing(
20406                            current_execution_position..current_execution_position,
20407                        )?;
20408
20409                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20410                    })?;
20411
20412                    let range =
20413                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20414
20415                    project.inline_values(buffer, range, cx)
20416                })
20417                .ok()
20418                .flatten()?
20419                .await
20420                .context("refreshing debugger inlays")
20421                .log_err()?;
20422
20423            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20424
20425            for (buffer_id, inline_value) in inline_values
20426                .into_iter()
20427                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20428            {
20429                buffer_inline_values
20430                    .entry(buffer_id)
20431                    .or_default()
20432                    .push(inline_value);
20433            }
20434
20435            editor
20436                .update(cx, |editor, cx| {
20437                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20438                    let mut new_inlays = Vec::default();
20439
20440                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20441                        let buffer_id = buffer_snapshot.remote_id();
20442                        buffer_inline_values
20443                            .get(&buffer_id)
20444                            .into_iter()
20445                            .flatten()
20446                            .for_each(|hint| {
20447                                let inlay = Inlay::debugger(
20448                                    post_inc(&mut editor.next_inlay_id),
20449                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20450                                    hint.text(),
20451                                );
20452                                if !inlay.text.chars().contains(&'\n') {
20453                                    new_inlays.push(inlay);
20454                                }
20455                            });
20456                    }
20457
20458                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20459                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20460
20461                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20462                })
20463                .ok()?;
20464            Some(())
20465        });
20466    }
20467
20468    fn on_buffer_event(
20469        &mut self,
20470        multibuffer: &Entity<MultiBuffer>,
20471        event: &multi_buffer::Event,
20472        window: &mut Window,
20473        cx: &mut Context<Self>,
20474    ) {
20475        match event {
20476            multi_buffer::Event::Edited {
20477                singleton_buffer_edited,
20478                edited_buffer,
20479            } => {
20480                self.scrollbar_marker_state.dirty = true;
20481                self.active_indent_guides_state.dirty = true;
20482                self.refresh_active_diagnostics(cx);
20483                self.refresh_code_actions(window, cx);
20484                self.refresh_selected_text_highlights(true, window, cx);
20485                self.refresh_single_line_folds(window, cx);
20486                refresh_matching_bracket_highlights(self, window, cx);
20487                if self.has_active_edit_prediction() {
20488                    self.update_visible_edit_prediction(window, cx);
20489                }
20490                if let Some(project) = self.project.as_ref()
20491                    && let Some(edited_buffer) = edited_buffer
20492                {
20493                    project.update(cx, |project, cx| {
20494                        self.registered_buffers
20495                            .entry(edited_buffer.read(cx).remote_id())
20496                            .or_insert_with(|| {
20497                                project.register_buffer_with_language_servers(edited_buffer, cx)
20498                            });
20499                    });
20500                }
20501                cx.emit(EditorEvent::BufferEdited);
20502                cx.emit(SearchEvent::MatchesInvalidated);
20503
20504                if let Some(buffer) = edited_buffer {
20505                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20506                }
20507
20508                if *singleton_buffer_edited {
20509                    if let Some(buffer) = edited_buffer
20510                        && buffer.read(cx).file().is_none()
20511                    {
20512                        cx.emit(EditorEvent::TitleChanged);
20513                    }
20514                    if let Some(project) = &self.project {
20515                        #[allow(clippy::mutable_key_type)]
20516                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20517                            multibuffer
20518                                .all_buffers()
20519                                .into_iter()
20520                                .filter_map(|buffer| {
20521                                    buffer.update(cx, |buffer, cx| {
20522                                        let language = buffer.language()?;
20523                                        let should_discard = project.update(cx, |project, cx| {
20524                                            project.is_local()
20525                                                && !project.has_language_servers_for(buffer, cx)
20526                                        });
20527                                        should_discard.not().then_some(language.clone())
20528                                    })
20529                                })
20530                                .collect::<HashSet<_>>()
20531                        });
20532                        if !languages_affected.is_empty() {
20533                            self.refresh_inlay_hints(
20534                                InlayHintRefreshReason::BufferEdited(languages_affected),
20535                                cx,
20536                            );
20537                        }
20538                    }
20539                }
20540
20541                let Some(project) = &self.project else { return };
20542                let (telemetry, is_via_ssh) = {
20543                    let project = project.read(cx);
20544                    let telemetry = project.client().telemetry().clone();
20545                    let is_via_ssh = project.is_via_remote_server();
20546                    (telemetry, is_via_ssh)
20547                };
20548                refresh_linked_ranges(self, window, cx);
20549                telemetry.log_edit_event("editor", is_via_ssh);
20550            }
20551            multi_buffer::Event::ExcerptsAdded {
20552                buffer,
20553                predecessor,
20554                excerpts,
20555            } => {
20556                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20557                let buffer_id = buffer.read(cx).remote_id();
20558                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20559                    && let Some(project) = &self.project
20560                {
20561                    update_uncommitted_diff_for_buffer(
20562                        cx.entity(),
20563                        project,
20564                        [buffer.clone()],
20565                        self.buffer.clone(),
20566                        cx,
20567                    )
20568                    .detach();
20569                }
20570                if self.active_diagnostics != ActiveDiagnostic::All {
20571                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20572                }
20573                cx.emit(EditorEvent::ExcerptsAdded {
20574                    buffer: buffer.clone(),
20575                    predecessor: *predecessor,
20576                    excerpts: excerpts.clone(),
20577                });
20578                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20579            }
20580            multi_buffer::Event::ExcerptsRemoved {
20581                ids,
20582                removed_buffer_ids,
20583            } => {
20584                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20585                let buffer = self.buffer.read(cx);
20586                self.registered_buffers
20587                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20588                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20589                cx.emit(EditorEvent::ExcerptsRemoved {
20590                    ids: ids.clone(),
20591                    removed_buffer_ids: removed_buffer_ids.clone(),
20592                });
20593            }
20594            multi_buffer::Event::ExcerptsEdited {
20595                excerpt_ids,
20596                buffer_ids,
20597            } => {
20598                self.display_map.update(cx, |map, cx| {
20599                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20600                });
20601                cx.emit(EditorEvent::ExcerptsEdited {
20602                    ids: excerpt_ids.clone(),
20603                });
20604            }
20605            multi_buffer::Event::ExcerptsExpanded { ids } => {
20606                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20607                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20608            }
20609            multi_buffer::Event::Reparsed(buffer_id) => {
20610                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20611                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20612
20613                cx.emit(EditorEvent::Reparsed(*buffer_id));
20614            }
20615            multi_buffer::Event::DiffHunksToggled => {
20616                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20617            }
20618            multi_buffer::Event::LanguageChanged(buffer_id) => {
20619                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20620                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20621                cx.emit(EditorEvent::Reparsed(*buffer_id));
20622                cx.notify();
20623            }
20624            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20625            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20626            multi_buffer::Event::FileHandleChanged
20627            | multi_buffer::Event::Reloaded
20628            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20629            multi_buffer::Event::DiagnosticsUpdated => {
20630                self.update_diagnostics_state(window, cx);
20631            }
20632            _ => {}
20633        };
20634    }
20635
20636    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20637        if !self.diagnostics_enabled() {
20638            return;
20639        }
20640        self.refresh_active_diagnostics(cx);
20641        self.refresh_inline_diagnostics(true, window, cx);
20642        self.scrollbar_marker_state.dirty = true;
20643        cx.notify();
20644    }
20645
20646    pub fn start_temporary_diff_override(&mut self) {
20647        self.load_diff_task.take();
20648        self.temporary_diff_override = true;
20649    }
20650
20651    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20652        self.temporary_diff_override = false;
20653        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20654        self.buffer.update(cx, |buffer, cx| {
20655            buffer.set_all_diff_hunks_collapsed(cx);
20656        });
20657
20658        if let Some(project) = self.project.clone() {
20659            self.load_diff_task = Some(
20660                update_uncommitted_diff_for_buffer(
20661                    cx.entity(),
20662                    &project,
20663                    self.buffer.read(cx).all_buffers(),
20664                    self.buffer.clone(),
20665                    cx,
20666                )
20667                .shared(),
20668            );
20669        }
20670    }
20671
20672    fn on_display_map_changed(
20673        &mut self,
20674        _: Entity<DisplayMap>,
20675        _: &mut Window,
20676        cx: &mut Context<Self>,
20677    ) {
20678        cx.notify();
20679    }
20680
20681    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20682        if self.diagnostics_enabled() {
20683            let new_severity = EditorSettings::get_global(cx)
20684                .diagnostics_max_severity
20685                .unwrap_or(DiagnosticSeverity::Hint);
20686            self.set_max_diagnostics_severity(new_severity, cx);
20687        }
20688        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20689        self.update_edit_prediction_settings(cx);
20690        self.refresh_edit_prediction(true, false, window, cx);
20691        self.refresh_inline_values(cx);
20692        self.refresh_inlay_hints(
20693            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20694                self.selections.newest_anchor().head(),
20695                &self.buffer.read(cx).snapshot(cx),
20696                cx,
20697            )),
20698            cx,
20699        );
20700
20701        let old_cursor_shape = self.cursor_shape;
20702        let old_show_breadcrumbs = self.show_breadcrumbs;
20703
20704        {
20705            let editor_settings = EditorSettings::get_global(cx);
20706            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20707            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20708            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20709            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20710        }
20711
20712        if old_cursor_shape != self.cursor_shape {
20713            cx.emit(EditorEvent::CursorShapeChanged);
20714        }
20715
20716        if old_show_breadcrumbs != self.show_breadcrumbs {
20717            cx.emit(EditorEvent::BreadcrumbsChanged);
20718        }
20719
20720        let project_settings = ProjectSettings::get_global(cx);
20721        self.serialize_dirty_buffers =
20722            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20723
20724        if self.mode.is_full() {
20725            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20726            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20727            if self.show_inline_diagnostics != show_inline_diagnostics {
20728                self.show_inline_diagnostics = show_inline_diagnostics;
20729                self.refresh_inline_diagnostics(false, window, cx);
20730            }
20731
20732            if self.git_blame_inline_enabled != inline_blame_enabled {
20733                self.toggle_git_blame_inline_internal(false, window, cx);
20734            }
20735
20736            let minimap_settings = EditorSettings::get_global(cx).minimap;
20737            if self.minimap_visibility != MinimapVisibility::Disabled {
20738                if self.minimap_visibility.settings_visibility()
20739                    != minimap_settings.minimap_enabled()
20740                {
20741                    self.set_minimap_visibility(
20742                        MinimapVisibility::for_mode(self.mode(), cx),
20743                        window,
20744                        cx,
20745                    );
20746                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20747                    minimap_entity.update(cx, |minimap_editor, cx| {
20748                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20749                    })
20750                }
20751            }
20752        }
20753
20754        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20755            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20756        }) {
20757            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20758                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20759            }
20760            self.refresh_colors(false, None, window, cx);
20761        }
20762
20763        cx.notify();
20764    }
20765
20766    pub fn set_searchable(&mut self, searchable: bool) {
20767        self.searchable = searchable;
20768    }
20769
20770    pub fn searchable(&self) -> bool {
20771        self.searchable
20772    }
20773
20774    fn open_proposed_changes_editor(
20775        &mut self,
20776        _: &OpenProposedChangesEditor,
20777        window: &mut Window,
20778        cx: &mut Context<Self>,
20779    ) {
20780        let Some(workspace) = self.workspace() else {
20781            cx.propagate();
20782            return;
20783        };
20784
20785        let selections = self.selections.all::<usize>(cx);
20786        let multi_buffer = self.buffer.read(cx);
20787        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20788        let mut new_selections_by_buffer = HashMap::default();
20789        for selection in selections {
20790            for (buffer, range, _) in
20791                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20792            {
20793                let mut range = range.to_point(buffer);
20794                range.start.column = 0;
20795                range.end.column = buffer.line_len(range.end.row);
20796                new_selections_by_buffer
20797                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20798                    .or_insert(Vec::new())
20799                    .push(range)
20800            }
20801        }
20802
20803        let proposed_changes_buffers = new_selections_by_buffer
20804            .into_iter()
20805            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20806            .collect::<Vec<_>>();
20807        let proposed_changes_editor = cx.new(|cx| {
20808            ProposedChangesEditor::new(
20809                "Proposed changes",
20810                proposed_changes_buffers,
20811                self.project.clone(),
20812                window,
20813                cx,
20814            )
20815        });
20816
20817        window.defer(cx, move |window, cx| {
20818            workspace.update(cx, |workspace, cx| {
20819                workspace.active_pane().update(cx, |pane, cx| {
20820                    pane.add_item(
20821                        Box::new(proposed_changes_editor),
20822                        true,
20823                        true,
20824                        None,
20825                        window,
20826                        cx,
20827                    );
20828                });
20829            });
20830        });
20831    }
20832
20833    pub fn open_excerpts_in_split(
20834        &mut self,
20835        _: &OpenExcerptsSplit,
20836        window: &mut Window,
20837        cx: &mut Context<Self>,
20838    ) {
20839        self.open_excerpts_common(None, true, window, cx)
20840    }
20841
20842    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20843        self.open_excerpts_common(None, false, window, cx)
20844    }
20845
20846    fn open_excerpts_common(
20847        &mut self,
20848        jump_data: Option<JumpData>,
20849        split: bool,
20850        window: &mut Window,
20851        cx: &mut Context<Self>,
20852    ) {
20853        let Some(workspace) = self.workspace() else {
20854            cx.propagate();
20855            return;
20856        };
20857
20858        if self.buffer.read(cx).is_singleton() {
20859            cx.propagate();
20860            return;
20861        }
20862
20863        let mut new_selections_by_buffer = HashMap::default();
20864        match &jump_data {
20865            Some(JumpData::MultiBufferPoint {
20866                excerpt_id,
20867                position,
20868                anchor,
20869                line_offset_from_top,
20870            }) => {
20871                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20872                if let Some(buffer) = multi_buffer_snapshot
20873                    .buffer_id_for_excerpt(*excerpt_id)
20874                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20875                {
20876                    let buffer_snapshot = buffer.read(cx).snapshot();
20877                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20878                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20879                    } else {
20880                        buffer_snapshot.clip_point(*position, Bias::Left)
20881                    };
20882                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20883                    new_selections_by_buffer.insert(
20884                        buffer,
20885                        (
20886                            vec![jump_to_offset..jump_to_offset],
20887                            Some(*line_offset_from_top),
20888                        ),
20889                    );
20890                }
20891            }
20892            Some(JumpData::MultiBufferRow {
20893                row,
20894                line_offset_from_top,
20895            }) => {
20896                let point = MultiBufferPoint::new(row.0, 0);
20897                if let Some((buffer, buffer_point, _)) =
20898                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20899                {
20900                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20901                    new_selections_by_buffer
20902                        .entry(buffer)
20903                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20904                        .0
20905                        .push(buffer_offset..buffer_offset)
20906                }
20907            }
20908            None => {
20909                let selections = self.selections.all::<usize>(cx);
20910                let multi_buffer = self.buffer.read(cx);
20911                for selection in selections {
20912                    for (snapshot, range, _, anchor) in multi_buffer
20913                        .snapshot(cx)
20914                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20915                    {
20916                        if let Some(anchor) = anchor {
20917                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20918                            else {
20919                                continue;
20920                            };
20921                            let offset = text::ToOffset::to_offset(
20922                                &anchor.text_anchor,
20923                                &buffer_handle.read(cx).snapshot(),
20924                            );
20925                            let range = offset..offset;
20926                            new_selections_by_buffer
20927                                .entry(buffer_handle)
20928                                .or_insert((Vec::new(), None))
20929                                .0
20930                                .push(range)
20931                        } else {
20932                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20933                            else {
20934                                continue;
20935                            };
20936                            new_selections_by_buffer
20937                                .entry(buffer_handle)
20938                                .or_insert((Vec::new(), None))
20939                                .0
20940                                .push(range)
20941                        }
20942                    }
20943                }
20944            }
20945        }
20946
20947        new_selections_by_buffer
20948            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20949
20950        if new_selections_by_buffer.is_empty() {
20951            return;
20952        }
20953
20954        // We defer the pane interaction because we ourselves are a workspace item
20955        // and activating a new item causes the pane to call a method on us reentrantly,
20956        // which panics if we're on the stack.
20957        window.defer(cx, move |window, cx| {
20958            workspace.update(cx, |workspace, cx| {
20959                let pane = if split {
20960                    workspace.adjacent_pane(window, cx)
20961                } else {
20962                    workspace.active_pane().clone()
20963                };
20964
20965                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20966                    let editor = buffer
20967                        .read(cx)
20968                        .file()
20969                        .is_none()
20970                        .then(|| {
20971                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20972                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20973                            // Instead, we try to activate the existing editor in the pane first.
20974                            let (editor, pane_item_index) =
20975                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20976                                    let editor = item.downcast::<Editor>()?;
20977                                    let singleton_buffer =
20978                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20979                                    if singleton_buffer == buffer {
20980                                        Some((editor, i))
20981                                    } else {
20982                                        None
20983                                    }
20984                                })?;
20985                            pane.update(cx, |pane, cx| {
20986                                pane.activate_item(pane_item_index, true, true, window, cx)
20987                            });
20988                            Some(editor)
20989                        })
20990                        .flatten()
20991                        .unwrap_or_else(|| {
20992                            workspace.open_project_item::<Self>(
20993                                pane.clone(),
20994                                buffer,
20995                                true,
20996                                true,
20997                                window,
20998                                cx,
20999                            )
21000                        });
21001
21002                    editor.update(cx, |editor, cx| {
21003                        let autoscroll = match scroll_offset {
21004                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21005                            None => Autoscroll::newest(),
21006                        };
21007                        let nav_history = editor.nav_history.take();
21008                        editor.change_selections(
21009                            SelectionEffects::scroll(autoscroll),
21010                            window,
21011                            cx,
21012                            |s| {
21013                                s.select_ranges(ranges);
21014                            },
21015                        );
21016                        editor.nav_history = nav_history;
21017                    });
21018                }
21019            })
21020        });
21021    }
21022
21023    // For now, don't allow opening excerpts in buffers that aren't backed by
21024    // regular project files.
21025    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21026        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21027    }
21028
21029    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21030        let snapshot = self.buffer.read(cx).read(cx);
21031        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21032        Some(
21033            ranges
21034                .iter()
21035                .map(move |range| {
21036                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21037                })
21038                .collect(),
21039        )
21040    }
21041
21042    fn selection_replacement_ranges(
21043        &self,
21044        range: Range<OffsetUtf16>,
21045        cx: &mut App,
21046    ) -> Vec<Range<OffsetUtf16>> {
21047        let selections = self.selections.all::<OffsetUtf16>(cx);
21048        let newest_selection = selections
21049            .iter()
21050            .max_by_key(|selection| selection.id)
21051            .unwrap();
21052        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21053        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21054        let snapshot = self.buffer.read(cx).read(cx);
21055        selections
21056            .into_iter()
21057            .map(|mut selection| {
21058                selection.start.0 =
21059                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21060                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21061                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21062                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21063            })
21064            .collect()
21065    }
21066
21067    fn report_editor_event(
21068        &self,
21069        reported_event: ReportEditorEvent,
21070        file_extension: Option<String>,
21071        cx: &App,
21072    ) {
21073        if cfg!(any(test, feature = "test-support")) {
21074            return;
21075        }
21076
21077        let Some(project) = &self.project else { return };
21078
21079        // If None, we are in a file without an extension
21080        let file = self
21081            .buffer
21082            .read(cx)
21083            .as_singleton()
21084            .and_then(|b| b.read(cx).file());
21085        let file_extension = file_extension.or(file
21086            .as_ref()
21087            .and_then(|file| Path::new(file.file_name(cx)).extension())
21088            .and_then(|e| e.to_str())
21089            .map(|a| a.to_string()));
21090
21091        let vim_mode = vim_enabled(cx);
21092
21093        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21094        let copilot_enabled = edit_predictions_provider
21095            == language::language_settings::EditPredictionProvider::Copilot;
21096        let copilot_enabled_for_language = self
21097            .buffer
21098            .read(cx)
21099            .language_settings(cx)
21100            .show_edit_predictions;
21101
21102        let project = project.read(cx);
21103        let event_type = reported_event.event_type();
21104
21105        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21106            telemetry::event!(
21107                event_type,
21108                type = if auto_saved {"autosave"} else {"manual"},
21109                file_extension,
21110                vim_mode,
21111                copilot_enabled,
21112                copilot_enabled_for_language,
21113                edit_predictions_provider,
21114                is_via_ssh = project.is_via_remote_server(),
21115            );
21116        } else {
21117            telemetry::event!(
21118                event_type,
21119                file_extension,
21120                vim_mode,
21121                copilot_enabled,
21122                copilot_enabled_for_language,
21123                edit_predictions_provider,
21124                is_via_ssh = project.is_via_remote_server(),
21125            );
21126        };
21127    }
21128
21129    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21130    /// with each line being an array of {text, highlight} objects.
21131    fn copy_highlight_json(
21132        &mut self,
21133        _: &CopyHighlightJson,
21134        window: &mut Window,
21135        cx: &mut Context<Self>,
21136    ) {
21137        #[derive(Serialize)]
21138        struct Chunk<'a> {
21139            text: String,
21140            highlight: Option<&'a str>,
21141        }
21142
21143        let snapshot = self.buffer.read(cx).snapshot(cx);
21144        let range = self
21145            .selected_text_range(false, window, cx)
21146            .and_then(|selection| {
21147                if selection.range.is_empty() {
21148                    None
21149                } else {
21150                    Some(selection.range)
21151                }
21152            })
21153            .unwrap_or_else(|| 0..snapshot.len());
21154
21155        let chunks = snapshot.chunks(range, true);
21156        let mut lines = Vec::new();
21157        let mut line: VecDeque<Chunk> = VecDeque::new();
21158
21159        let Some(style) = self.style.as_ref() else {
21160            return;
21161        };
21162
21163        for chunk in chunks {
21164            let highlight = chunk
21165                .syntax_highlight_id
21166                .and_then(|id| id.name(&style.syntax));
21167            let mut chunk_lines = chunk.text.split('\n').peekable();
21168            while let Some(text) = chunk_lines.next() {
21169                let mut merged_with_last_token = false;
21170                if let Some(last_token) = line.back_mut()
21171                    && last_token.highlight == highlight
21172                {
21173                    last_token.text.push_str(text);
21174                    merged_with_last_token = true;
21175                }
21176
21177                if !merged_with_last_token {
21178                    line.push_back(Chunk {
21179                        text: text.into(),
21180                        highlight,
21181                    });
21182                }
21183
21184                if chunk_lines.peek().is_some() {
21185                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21186                        line.pop_front();
21187                    }
21188                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21189                        line.pop_back();
21190                    }
21191
21192                    lines.push(mem::take(&mut line));
21193                }
21194            }
21195        }
21196
21197        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21198            return;
21199        };
21200        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21201    }
21202
21203    pub fn open_context_menu(
21204        &mut self,
21205        _: &OpenContextMenu,
21206        window: &mut Window,
21207        cx: &mut Context<Self>,
21208    ) {
21209        self.request_autoscroll(Autoscroll::newest(), cx);
21210        let position = self.selections.newest_display(cx).start;
21211        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21212    }
21213
21214    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21215        &self.inlay_hint_cache
21216    }
21217
21218    pub fn replay_insert_event(
21219        &mut self,
21220        text: &str,
21221        relative_utf16_range: Option<Range<isize>>,
21222        window: &mut Window,
21223        cx: &mut Context<Self>,
21224    ) {
21225        if !self.input_enabled {
21226            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21227            return;
21228        }
21229        if let Some(relative_utf16_range) = relative_utf16_range {
21230            let selections = self.selections.all::<OffsetUtf16>(cx);
21231            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21232                let new_ranges = selections.into_iter().map(|range| {
21233                    let start = OffsetUtf16(
21234                        range
21235                            .head()
21236                            .0
21237                            .saturating_add_signed(relative_utf16_range.start),
21238                    );
21239                    let end = OffsetUtf16(
21240                        range
21241                            .head()
21242                            .0
21243                            .saturating_add_signed(relative_utf16_range.end),
21244                    );
21245                    start..end
21246                });
21247                s.select_ranges(new_ranges);
21248            });
21249        }
21250
21251        self.handle_input(text, window, cx);
21252    }
21253
21254    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21255        let Some(provider) = self.semantics_provider.as_ref() else {
21256            return false;
21257        };
21258
21259        let mut supports = false;
21260        self.buffer().update(cx, |this, cx| {
21261            this.for_each_buffer(|buffer| {
21262                supports |= provider.supports_inlay_hints(buffer, cx);
21263            });
21264        });
21265
21266        supports
21267    }
21268
21269    pub fn is_focused(&self, window: &Window) -> bool {
21270        self.focus_handle.is_focused(window)
21271    }
21272
21273    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21274        cx.emit(EditorEvent::Focused);
21275
21276        if let Some(descendant) = self
21277            .last_focused_descendant
21278            .take()
21279            .and_then(|descendant| descendant.upgrade())
21280        {
21281            window.focus(&descendant);
21282        } else {
21283            if let Some(blame) = self.blame.as_ref() {
21284                blame.update(cx, GitBlame::focus)
21285            }
21286
21287            self.blink_manager.update(cx, BlinkManager::enable);
21288            self.show_cursor_names(window, cx);
21289            self.buffer.update(cx, |buffer, cx| {
21290                buffer.finalize_last_transaction(cx);
21291                if self.leader_id.is_none() {
21292                    buffer.set_active_selections(
21293                        &self.selections.disjoint_anchors_arc(),
21294                        self.selections.line_mode,
21295                        self.cursor_shape,
21296                        cx,
21297                    );
21298                }
21299            });
21300        }
21301    }
21302
21303    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21304        cx.emit(EditorEvent::FocusedIn)
21305    }
21306
21307    fn handle_focus_out(
21308        &mut self,
21309        event: FocusOutEvent,
21310        _window: &mut Window,
21311        cx: &mut Context<Self>,
21312    ) {
21313        if event.blurred != self.focus_handle {
21314            self.last_focused_descendant = Some(event.blurred);
21315        }
21316        self.selection_drag_state = SelectionDragState::None;
21317        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21318    }
21319
21320    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21321        self.blink_manager.update(cx, BlinkManager::disable);
21322        self.buffer
21323            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21324
21325        if let Some(blame) = self.blame.as_ref() {
21326            blame.update(cx, GitBlame::blur)
21327        }
21328        if !self.hover_state.focused(window, cx) {
21329            hide_hover(self, cx);
21330        }
21331        if !self
21332            .context_menu
21333            .borrow()
21334            .as_ref()
21335            .is_some_and(|context_menu| context_menu.focused(window, cx))
21336        {
21337            self.hide_context_menu(window, cx);
21338        }
21339        self.discard_edit_prediction(false, cx);
21340        cx.emit(EditorEvent::Blurred);
21341        cx.notify();
21342    }
21343
21344    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21345        let mut pending: String = window
21346            .pending_input_keystrokes()
21347            .into_iter()
21348            .flatten()
21349            .filter_map(|keystroke| {
21350                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21351                    keystroke.key_char.clone()
21352                } else {
21353                    None
21354                }
21355            })
21356            .collect();
21357
21358        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21359            pending = "".to_string();
21360        }
21361
21362        let existing_pending = self
21363            .text_highlights::<PendingInput>(cx)
21364            .map(|(_, ranges)| ranges.to_vec());
21365        if existing_pending.is_none() && pending.is_empty() {
21366            return;
21367        }
21368        let transaction =
21369            self.transact(window, cx, |this, window, cx| {
21370                let selections = this.selections.all::<usize>(cx);
21371                let edits = selections
21372                    .iter()
21373                    .map(|selection| (selection.end..selection.end, pending.clone()));
21374                this.edit(edits, cx);
21375                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21376                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21377                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21378                    }));
21379                });
21380                if let Some(existing_ranges) = existing_pending {
21381                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21382                    this.edit(edits, cx);
21383                }
21384            });
21385
21386        let snapshot = self.snapshot(window, cx);
21387        let ranges = self
21388            .selections
21389            .all::<usize>(cx)
21390            .into_iter()
21391            .map(|selection| {
21392                snapshot.buffer_snapshot.anchor_after(selection.end)
21393                    ..snapshot
21394                        .buffer_snapshot
21395                        .anchor_before(selection.end + pending.len())
21396            })
21397            .collect();
21398
21399        if pending.is_empty() {
21400            self.clear_highlights::<PendingInput>(cx);
21401        } else {
21402            self.highlight_text::<PendingInput>(
21403                ranges,
21404                HighlightStyle {
21405                    underline: Some(UnderlineStyle {
21406                        thickness: px(1.),
21407                        color: None,
21408                        wavy: false,
21409                    }),
21410                    ..Default::default()
21411                },
21412                cx,
21413            );
21414        }
21415
21416        self.ime_transaction = self.ime_transaction.or(transaction);
21417        if let Some(transaction) = self.ime_transaction {
21418            self.buffer.update(cx, |buffer, cx| {
21419                buffer.group_until_transaction(transaction, cx);
21420            });
21421        }
21422
21423        if self.text_highlights::<PendingInput>(cx).is_none() {
21424            self.ime_transaction.take();
21425        }
21426    }
21427
21428    pub fn register_action_renderer(
21429        &mut self,
21430        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21431    ) -> Subscription {
21432        let id = self.next_editor_action_id.post_inc();
21433        self.editor_actions
21434            .borrow_mut()
21435            .insert(id, Box::new(listener));
21436
21437        let editor_actions = self.editor_actions.clone();
21438        Subscription::new(move || {
21439            editor_actions.borrow_mut().remove(&id);
21440        })
21441    }
21442
21443    pub fn register_action<A: Action>(
21444        &mut self,
21445        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21446    ) -> Subscription {
21447        let id = self.next_editor_action_id.post_inc();
21448        let listener = Arc::new(listener);
21449        self.editor_actions.borrow_mut().insert(
21450            id,
21451            Box::new(move |_, window, _| {
21452                let listener = listener.clone();
21453                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21454                    let action = action.downcast_ref().unwrap();
21455                    if phase == DispatchPhase::Bubble {
21456                        listener(action, window, cx)
21457                    }
21458                })
21459            }),
21460        );
21461
21462        let editor_actions = self.editor_actions.clone();
21463        Subscription::new(move || {
21464            editor_actions.borrow_mut().remove(&id);
21465        })
21466    }
21467
21468    pub fn file_header_size(&self) -> u32 {
21469        FILE_HEADER_HEIGHT
21470    }
21471
21472    pub fn restore(
21473        &mut self,
21474        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21475        window: &mut Window,
21476        cx: &mut Context<Self>,
21477    ) {
21478        let workspace = self.workspace();
21479        let project = self.project();
21480        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21481            let mut tasks = Vec::new();
21482            for (buffer_id, changes) in revert_changes {
21483                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21484                    buffer.update(cx, |buffer, cx| {
21485                        buffer.edit(
21486                            changes
21487                                .into_iter()
21488                                .map(|(range, text)| (range, text.to_string())),
21489                            None,
21490                            cx,
21491                        );
21492                    });
21493
21494                    if let Some(project) =
21495                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21496                    {
21497                        project.update(cx, |project, cx| {
21498                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21499                        })
21500                    }
21501                }
21502            }
21503            tasks
21504        });
21505        cx.spawn_in(window, async move |_, cx| {
21506            for (buffer, task) in save_tasks {
21507                let result = task.await;
21508                if result.is_err() {
21509                    let Some(path) = buffer
21510                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21511                        .ok()
21512                    else {
21513                        continue;
21514                    };
21515                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21516                        let Some(task) = cx
21517                            .update_window_entity(workspace, |workspace, window, cx| {
21518                                workspace
21519                                    .open_path_preview(path, None, false, false, false, window, cx)
21520                            })
21521                            .ok()
21522                        else {
21523                            continue;
21524                        };
21525                        task.await.log_err();
21526                    }
21527                }
21528            }
21529        })
21530        .detach();
21531        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21532            selections.refresh()
21533        });
21534    }
21535
21536    pub fn to_pixel_point(
21537        &self,
21538        source: multi_buffer::Anchor,
21539        editor_snapshot: &EditorSnapshot,
21540        window: &mut Window,
21541    ) -> Option<gpui::Point<Pixels>> {
21542        let source_point = source.to_display_point(editor_snapshot);
21543        self.display_to_pixel_point(source_point, editor_snapshot, window)
21544    }
21545
21546    pub fn display_to_pixel_point(
21547        &self,
21548        source: DisplayPoint,
21549        editor_snapshot: &EditorSnapshot,
21550        window: &mut Window,
21551    ) -> Option<gpui::Point<Pixels>> {
21552        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21553        let text_layout_details = self.text_layout_details(window);
21554        let scroll_top = text_layout_details
21555            .scroll_anchor
21556            .scroll_position(editor_snapshot)
21557            .y;
21558
21559        if source.row().as_f32() < scroll_top.floor() {
21560            return None;
21561        }
21562        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21563        let source_y = line_height * (source.row().as_f32() - scroll_top);
21564        Some(gpui::Point::new(source_x, source_y))
21565    }
21566
21567    pub fn has_visible_completions_menu(&self) -> bool {
21568        !self.edit_prediction_preview_is_active()
21569            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21570                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21571            })
21572    }
21573
21574    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21575        if self.mode.is_minimap() {
21576            return;
21577        }
21578        self.addons
21579            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21580    }
21581
21582    pub fn unregister_addon<T: Addon>(&mut self) {
21583        self.addons.remove(&std::any::TypeId::of::<T>());
21584    }
21585
21586    pub fn addon<T: Addon>(&self) -> Option<&T> {
21587        let type_id = std::any::TypeId::of::<T>();
21588        self.addons
21589            .get(&type_id)
21590            .and_then(|item| item.to_any().downcast_ref::<T>())
21591    }
21592
21593    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21594        let type_id = std::any::TypeId::of::<T>();
21595        self.addons
21596            .get_mut(&type_id)
21597            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21598    }
21599
21600    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21601        let text_layout_details = self.text_layout_details(window);
21602        let style = &text_layout_details.editor_style;
21603        let font_id = window.text_system().resolve_font(&style.text.font());
21604        let font_size = style.text.font_size.to_pixels(window.rem_size());
21605        let line_height = style.text.line_height_in_pixels(window.rem_size());
21606        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21607        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21608
21609        CharacterDimensions {
21610            em_width,
21611            em_advance,
21612            line_height,
21613        }
21614    }
21615
21616    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21617        self.load_diff_task.clone()
21618    }
21619
21620    fn read_metadata_from_db(
21621        &mut self,
21622        item_id: u64,
21623        workspace_id: WorkspaceId,
21624        window: &mut Window,
21625        cx: &mut Context<Editor>,
21626    ) {
21627        if self.is_singleton(cx)
21628            && !self.mode.is_minimap()
21629            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21630        {
21631            let buffer_snapshot = OnceCell::new();
21632
21633            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21634                && !folds.is_empty()
21635            {
21636                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21637                self.fold_ranges(
21638                    folds
21639                        .into_iter()
21640                        .map(|(start, end)| {
21641                            snapshot.clip_offset(start, Bias::Left)
21642                                ..snapshot.clip_offset(end, Bias::Right)
21643                        })
21644                        .collect(),
21645                    false,
21646                    window,
21647                    cx,
21648                );
21649            }
21650
21651            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21652                && !selections.is_empty()
21653            {
21654                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21655                // skip adding the initial selection to selection history
21656                self.selection_history.mode = SelectionHistoryMode::Skipping;
21657                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21658                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21659                        snapshot.clip_offset(start, Bias::Left)
21660                            ..snapshot.clip_offset(end, Bias::Right)
21661                    }));
21662                });
21663                self.selection_history.mode = SelectionHistoryMode::Normal;
21664            };
21665        }
21666
21667        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21668    }
21669
21670    fn update_lsp_data(
21671        &mut self,
21672        ignore_cache: bool,
21673        for_buffer: Option<BufferId>,
21674        window: &mut Window,
21675        cx: &mut Context<'_, Self>,
21676    ) {
21677        self.pull_diagnostics(for_buffer, window, cx);
21678        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21679    }
21680}
21681
21682fn vim_enabled(cx: &App) -> bool {
21683    cx.global::<SettingsStore>()
21684        .raw_user_settings()
21685        .get("vim_mode")
21686        == Some(&serde_json::Value::Bool(true))
21687}
21688
21689fn process_completion_for_edit(
21690    completion: &Completion,
21691    intent: CompletionIntent,
21692    buffer: &Entity<Buffer>,
21693    cursor_position: &text::Anchor,
21694    cx: &mut Context<Editor>,
21695) -> CompletionEdit {
21696    let buffer = buffer.read(cx);
21697    let buffer_snapshot = buffer.snapshot();
21698    let (snippet, new_text) = if completion.is_snippet() {
21699        // Workaround for typescript language server issues so that methods don't expand within
21700        // strings and functions with type expressions. The previous point is used because the query
21701        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21702        let mut snippet_source = completion.new_text.clone();
21703        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21704        previous_point.column = previous_point.column.saturating_sub(1);
21705        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21706            && scope.prefers_label_for_snippet_in_completion()
21707            && let Some(label) = completion.label()
21708            && matches!(
21709                completion.kind(),
21710                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21711            )
21712        {
21713            snippet_source = label;
21714        }
21715        match Snippet::parse(&snippet_source).log_err() {
21716            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21717            None => (None, completion.new_text.clone()),
21718        }
21719    } else {
21720        (None, completion.new_text.clone())
21721    };
21722
21723    let mut range_to_replace = {
21724        let replace_range = &completion.replace_range;
21725        if let CompletionSource::Lsp {
21726            insert_range: Some(insert_range),
21727            ..
21728        } = &completion.source
21729        {
21730            debug_assert_eq!(
21731                insert_range.start, replace_range.start,
21732                "insert_range and replace_range should start at the same position"
21733            );
21734            debug_assert!(
21735                insert_range
21736                    .start
21737                    .cmp(cursor_position, &buffer_snapshot)
21738                    .is_le(),
21739                "insert_range should start before or at cursor position"
21740            );
21741            debug_assert!(
21742                replace_range
21743                    .start
21744                    .cmp(cursor_position, &buffer_snapshot)
21745                    .is_le(),
21746                "replace_range should start before or at cursor position"
21747            );
21748
21749            let should_replace = match intent {
21750                CompletionIntent::CompleteWithInsert => false,
21751                CompletionIntent::CompleteWithReplace => true,
21752                CompletionIntent::Complete | CompletionIntent::Compose => {
21753                    let insert_mode =
21754                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21755                            .completions
21756                            .lsp_insert_mode;
21757                    match insert_mode {
21758                        LspInsertMode::Insert => false,
21759                        LspInsertMode::Replace => true,
21760                        LspInsertMode::ReplaceSubsequence => {
21761                            let mut text_to_replace = buffer.chars_for_range(
21762                                buffer.anchor_before(replace_range.start)
21763                                    ..buffer.anchor_after(replace_range.end),
21764                            );
21765                            let mut current_needle = text_to_replace.next();
21766                            for haystack_ch in completion.label.text.chars() {
21767                                if let Some(needle_ch) = current_needle
21768                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21769                                {
21770                                    current_needle = text_to_replace.next();
21771                                }
21772                            }
21773                            current_needle.is_none()
21774                        }
21775                        LspInsertMode::ReplaceSuffix => {
21776                            if replace_range
21777                                .end
21778                                .cmp(cursor_position, &buffer_snapshot)
21779                                .is_gt()
21780                            {
21781                                let range_after_cursor = *cursor_position..replace_range.end;
21782                                let text_after_cursor = buffer
21783                                    .text_for_range(
21784                                        buffer.anchor_before(range_after_cursor.start)
21785                                            ..buffer.anchor_after(range_after_cursor.end),
21786                                    )
21787                                    .collect::<String>()
21788                                    .to_ascii_lowercase();
21789                                completion
21790                                    .label
21791                                    .text
21792                                    .to_ascii_lowercase()
21793                                    .ends_with(&text_after_cursor)
21794                            } else {
21795                                true
21796                            }
21797                        }
21798                    }
21799                }
21800            };
21801
21802            if should_replace {
21803                replace_range.clone()
21804            } else {
21805                insert_range.clone()
21806            }
21807        } else {
21808            replace_range.clone()
21809        }
21810    };
21811
21812    if range_to_replace
21813        .end
21814        .cmp(cursor_position, &buffer_snapshot)
21815        .is_lt()
21816    {
21817        range_to_replace.end = *cursor_position;
21818    }
21819
21820    CompletionEdit {
21821        new_text,
21822        replace_range: range_to_replace.to_offset(buffer),
21823        snippet,
21824    }
21825}
21826
21827struct CompletionEdit {
21828    new_text: String,
21829    replace_range: Range<usize>,
21830    snippet: Option<Snippet>,
21831}
21832
21833fn insert_extra_newline_brackets(
21834    buffer: &MultiBufferSnapshot,
21835    range: Range<usize>,
21836    language: &language::LanguageScope,
21837) -> bool {
21838    let leading_whitespace_len = buffer
21839        .reversed_chars_at(range.start)
21840        .take_while(|c| c.is_whitespace() && *c != '\n')
21841        .map(|c| c.len_utf8())
21842        .sum::<usize>();
21843    let trailing_whitespace_len = buffer
21844        .chars_at(range.end)
21845        .take_while(|c| c.is_whitespace() && *c != '\n')
21846        .map(|c| c.len_utf8())
21847        .sum::<usize>();
21848    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21849
21850    language.brackets().any(|(pair, enabled)| {
21851        let pair_start = pair.start.trim_end();
21852        let pair_end = pair.end.trim_start();
21853
21854        enabled
21855            && pair.newline
21856            && buffer.contains_str_at(range.end, pair_end)
21857            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21858    })
21859}
21860
21861fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21862    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21863        [(buffer, range, _)] => (*buffer, range.clone()),
21864        _ => return false,
21865    };
21866    let pair = {
21867        let mut result: Option<BracketMatch> = None;
21868
21869        for pair in buffer
21870            .all_bracket_ranges(range.clone())
21871            .filter(move |pair| {
21872                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21873            })
21874        {
21875            let len = pair.close_range.end - pair.open_range.start;
21876
21877            if let Some(existing) = &result {
21878                let existing_len = existing.close_range.end - existing.open_range.start;
21879                if len > existing_len {
21880                    continue;
21881                }
21882            }
21883
21884            result = Some(pair);
21885        }
21886
21887        result
21888    };
21889    let Some(pair) = pair else {
21890        return false;
21891    };
21892    pair.newline_only
21893        && buffer
21894            .chars_for_range(pair.open_range.end..range.start)
21895            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21896            .all(|c| c.is_whitespace() && c != '\n')
21897}
21898
21899fn update_uncommitted_diff_for_buffer(
21900    editor: Entity<Editor>,
21901    project: &Entity<Project>,
21902    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21903    buffer: Entity<MultiBuffer>,
21904    cx: &mut App,
21905) -> Task<()> {
21906    let mut tasks = Vec::new();
21907    project.update(cx, |project, cx| {
21908        for buffer in buffers {
21909            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21910                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21911            }
21912        }
21913    });
21914    cx.spawn(async move |cx| {
21915        let diffs = future::join_all(tasks).await;
21916        if editor
21917            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21918            .unwrap_or(false)
21919        {
21920            return;
21921        }
21922
21923        buffer
21924            .update(cx, |buffer, cx| {
21925                for diff in diffs.into_iter().flatten() {
21926                    buffer.add_diff(diff, cx);
21927                }
21928            })
21929            .ok();
21930    })
21931}
21932
21933fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21934    let tab_size = tab_size.get() as usize;
21935    let mut width = offset;
21936
21937    for ch in text.chars() {
21938        width += if ch == '\t' {
21939            tab_size - (width % tab_size)
21940        } else {
21941            1
21942        };
21943    }
21944
21945    width - offset
21946}
21947
21948#[cfg(test)]
21949mod tests {
21950    use super::*;
21951
21952    #[test]
21953    fn test_string_size_with_expanded_tabs() {
21954        let nz = |val| NonZeroU32::new(val).unwrap();
21955        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21956        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21957        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21958        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21959        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21960        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21961        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21962        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21963    }
21964}
21965
21966/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21967struct WordBreakingTokenizer<'a> {
21968    input: &'a str,
21969}
21970
21971impl<'a> WordBreakingTokenizer<'a> {
21972    fn new(input: &'a str) -> Self {
21973        Self { input }
21974    }
21975}
21976
21977fn is_char_ideographic(ch: char) -> bool {
21978    use unicode_script::Script::*;
21979    use unicode_script::UnicodeScript;
21980    matches!(ch.script(), Han | Tangut | Yi)
21981}
21982
21983fn is_grapheme_ideographic(text: &str) -> bool {
21984    text.chars().any(is_char_ideographic)
21985}
21986
21987fn is_grapheme_whitespace(text: &str) -> bool {
21988    text.chars().any(|x| x.is_whitespace())
21989}
21990
21991fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21992    text.chars()
21993        .next()
21994        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21995}
21996
21997#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21998enum WordBreakToken<'a> {
21999    Word { token: &'a str, grapheme_len: usize },
22000    InlineWhitespace { token: &'a str, grapheme_len: usize },
22001    Newline,
22002}
22003
22004impl<'a> Iterator for WordBreakingTokenizer<'a> {
22005    /// Yields a span, the count of graphemes in the token, and whether it was
22006    /// whitespace. Note that it also breaks at word boundaries.
22007    type Item = WordBreakToken<'a>;
22008
22009    fn next(&mut self) -> Option<Self::Item> {
22010        use unicode_segmentation::UnicodeSegmentation;
22011        if self.input.is_empty() {
22012            return None;
22013        }
22014
22015        let mut iter = self.input.graphemes(true).peekable();
22016        let mut offset = 0;
22017        let mut grapheme_len = 0;
22018        if let Some(first_grapheme) = iter.next() {
22019            let is_newline = first_grapheme == "\n";
22020            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22021            offset += first_grapheme.len();
22022            grapheme_len += 1;
22023            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22024                if let Some(grapheme) = iter.peek().copied()
22025                    && should_stay_with_preceding_ideograph(grapheme)
22026                {
22027                    offset += grapheme.len();
22028                    grapheme_len += 1;
22029                }
22030            } else {
22031                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22032                let mut next_word_bound = words.peek().copied();
22033                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22034                    next_word_bound = words.next();
22035                }
22036                while let Some(grapheme) = iter.peek().copied() {
22037                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22038                        break;
22039                    };
22040                    if is_grapheme_whitespace(grapheme) != is_whitespace
22041                        || (grapheme == "\n") != is_newline
22042                    {
22043                        break;
22044                    };
22045                    offset += grapheme.len();
22046                    grapheme_len += 1;
22047                    iter.next();
22048                }
22049            }
22050            let token = &self.input[..offset];
22051            self.input = &self.input[offset..];
22052            if token == "\n" {
22053                Some(WordBreakToken::Newline)
22054            } else if is_whitespace {
22055                Some(WordBreakToken::InlineWhitespace {
22056                    token,
22057                    grapheme_len,
22058                })
22059            } else {
22060                Some(WordBreakToken::Word {
22061                    token,
22062                    grapheme_len,
22063                })
22064            }
22065        } else {
22066            None
22067        }
22068    }
22069}
22070
22071#[test]
22072fn test_word_breaking_tokenizer() {
22073    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22074        ("", &[]),
22075        ("  ", &[whitespace("  ", 2)]),
22076        ("Ʒ", &[word("Ʒ", 1)]),
22077        ("Ǽ", &[word("Ǽ", 1)]),
22078        ("", &[word("", 1)]),
22079        ("⋑⋑", &[word("⋑⋑", 2)]),
22080        (
22081            "原理,进而",
22082            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22083        ),
22084        (
22085            "hello world",
22086            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22087        ),
22088        (
22089            "hello, world",
22090            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22091        ),
22092        (
22093            "  hello world",
22094            &[
22095                whitespace("  ", 2),
22096                word("hello", 5),
22097                whitespace(" ", 1),
22098                word("world", 5),
22099            ],
22100        ),
22101        (
22102            "这是什么 \n 钢笔",
22103            &[
22104                word("", 1),
22105                word("", 1),
22106                word("", 1),
22107                word("", 1),
22108                whitespace(" ", 1),
22109                newline(),
22110                whitespace(" ", 1),
22111                word("", 1),
22112                word("", 1),
22113            ],
22114        ),
22115        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22116    ];
22117
22118    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22119        WordBreakToken::Word {
22120            token,
22121            grapheme_len,
22122        }
22123    }
22124
22125    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22126        WordBreakToken::InlineWhitespace {
22127            token,
22128            grapheme_len,
22129        }
22130    }
22131
22132    fn newline() -> WordBreakToken<'static> {
22133        WordBreakToken::Newline
22134    }
22135
22136    for (input, result) in tests {
22137        assert_eq!(
22138            WordBreakingTokenizer::new(input)
22139                .collect::<Vec<_>>()
22140                .as_slice(),
22141            *result,
22142        );
22143    }
22144}
22145
22146fn wrap_with_prefix(
22147    first_line_prefix: String,
22148    subsequent_lines_prefix: String,
22149    unwrapped_text: String,
22150    wrap_column: usize,
22151    tab_size: NonZeroU32,
22152    preserve_existing_whitespace: bool,
22153) -> String {
22154    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22155    let subsequent_lines_prefix_len =
22156        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22157    let mut wrapped_text = String::new();
22158    let mut current_line = first_line_prefix;
22159    let mut is_first_line = true;
22160
22161    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22162    let mut current_line_len = first_line_prefix_len;
22163    let mut in_whitespace = false;
22164    for token in tokenizer {
22165        let have_preceding_whitespace = in_whitespace;
22166        match token {
22167            WordBreakToken::Word {
22168                token,
22169                grapheme_len,
22170            } => {
22171                in_whitespace = false;
22172                let current_prefix_len = if is_first_line {
22173                    first_line_prefix_len
22174                } else {
22175                    subsequent_lines_prefix_len
22176                };
22177                if current_line_len + grapheme_len > wrap_column
22178                    && current_line_len != current_prefix_len
22179                {
22180                    wrapped_text.push_str(current_line.trim_end());
22181                    wrapped_text.push('\n');
22182                    is_first_line = false;
22183                    current_line = subsequent_lines_prefix.clone();
22184                    current_line_len = subsequent_lines_prefix_len;
22185                }
22186                current_line.push_str(token);
22187                current_line_len += grapheme_len;
22188            }
22189            WordBreakToken::InlineWhitespace {
22190                mut token,
22191                mut grapheme_len,
22192            } => {
22193                in_whitespace = true;
22194                if have_preceding_whitespace && !preserve_existing_whitespace {
22195                    continue;
22196                }
22197                if !preserve_existing_whitespace {
22198                    token = " ";
22199                    grapheme_len = 1;
22200                }
22201                let current_prefix_len = if is_first_line {
22202                    first_line_prefix_len
22203                } else {
22204                    subsequent_lines_prefix_len
22205                };
22206                if current_line_len + grapheme_len > wrap_column {
22207                    wrapped_text.push_str(current_line.trim_end());
22208                    wrapped_text.push('\n');
22209                    is_first_line = false;
22210                    current_line = subsequent_lines_prefix.clone();
22211                    current_line_len = subsequent_lines_prefix_len;
22212                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22213                    current_line.push_str(token);
22214                    current_line_len += grapheme_len;
22215                }
22216            }
22217            WordBreakToken::Newline => {
22218                in_whitespace = true;
22219                let current_prefix_len = if is_first_line {
22220                    first_line_prefix_len
22221                } else {
22222                    subsequent_lines_prefix_len
22223                };
22224                if preserve_existing_whitespace {
22225                    wrapped_text.push_str(current_line.trim_end());
22226                    wrapped_text.push('\n');
22227                    is_first_line = false;
22228                    current_line = subsequent_lines_prefix.clone();
22229                    current_line_len = subsequent_lines_prefix_len;
22230                } else if have_preceding_whitespace {
22231                    continue;
22232                } else if current_line_len + 1 > wrap_column
22233                    && current_line_len != current_prefix_len
22234                {
22235                    wrapped_text.push_str(current_line.trim_end());
22236                    wrapped_text.push('\n');
22237                    is_first_line = false;
22238                    current_line = subsequent_lines_prefix.clone();
22239                    current_line_len = subsequent_lines_prefix_len;
22240                } else if current_line_len != current_prefix_len {
22241                    current_line.push(' ');
22242                    current_line_len += 1;
22243                }
22244            }
22245        }
22246    }
22247
22248    if !current_line.is_empty() {
22249        wrapped_text.push_str(&current_line);
22250    }
22251    wrapped_text
22252}
22253
22254#[test]
22255fn test_wrap_with_prefix() {
22256    assert_eq!(
22257        wrap_with_prefix(
22258            "# ".to_string(),
22259            "# ".to_string(),
22260            "abcdefg".to_string(),
22261            4,
22262            NonZeroU32::new(4).unwrap(),
22263            false,
22264        ),
22265        "# abcdefg"
22266    );
22267    assert_eq!(
22268        wrap_with_prefix(
22269            "".to_string(),
22270            "".to_string(),
22271            "\thello world".to_string(),
22272            8,
22273            NonZeroU32::new(4).unwrap(),
22274            false,
22275        ),
22276        "hello\nworld"
22277    );
22278    assert_eq!(
22279        wrap_with_prefix(
22280            "// ".to_string(),
22281            "// ".to_string(),
22282            "xx \nyy zz aa bb cc".to_string(),
22283            12,
22284            NonZeroU32::new(4).unwrap(),
22285            false,
22286        ),
22287        "// xx yy zz\n// aa bb cc"
22288    );
22289    assert_eq!(
22290        wrap_with_prefix(
22291            String::new(),
22292            String::new(),
22293            "这是什么 \n 钢笔".to_string(),
22294            3,
22295            NonZeroU32::new(4).unwrap(),
22296            false,
22297        ),
22298        "这是什\n么 钢\n"
22299    );
22300}
22301
22302pub trait CollaborationHub {
22303    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22304    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22305    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22306}
22307
22308impl CollaborationHub for Entity<Project> {
22309    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22310        self.read(cx).collaborators()
22311    }
22312
22313    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22314        self.read(cx).user_store().read(cx).participant_indices()
22315    }
22316
22317    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22318        let this = self.read(cx);
22319        let user_ids = this.collaborators().values().map(|c| c.user_id);
22320        this.user_store().read(cx).participant_names(user_ids, cx)
22321    }
22322}
22323
22324pub trait SemanticsProvider {
22325    fn hover(
22326        &self,
22327        buffer: &Entity<Buffer>,
22328        position: text::Anchor,
22329        cx: &mut App,
22330    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22331
22332    fn inline_values(
22333        &self,
22334        buffer_handle: Entity<Buffer>,
22335        range: Range<text::Anchor>,
22336        cx: &mut App,
22337    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22338
22339    fn inlay_hints(
22340        &self,
22341        buffer_handle: Entity<Buffer>,
22342        range: Range<text::Anchor>,
22343        cx: &mut App,
22344    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22345
22346    fn resolve_inlay_hint(
22347        &self,
22348        hint: InlayHint,
22349        buffer_handle: Entity<Buffer>,
22350        server_id: LanguageServerId,
22351        cx: &mut App,
22352    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22353
22354    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22355
22356    fn document_highlights(
22357        &self,
22358        buffer: &Entity<Buffer>,
22359        position: text::Anchor,
22360        cx: &mut App,
22361    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22362
22363    fn definitions(
22364        &self,
22365        buffer: &Entity<Buffer>,
22366        position: text::Anchor,
22367        kind: GotoDefinitionKind,
22368        cx: &mut App,
22369    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22370
22371    fn range_for_rename(
22372        &self,
22373        buffer: &Entity<Buffer>,
22374        position: text::Anchor,
22375        cx: &mut App,
22376    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22377
22378    fn perform_rename(
22379        &self,
22380        buffer: &Entity<Buffer>,
22381        position: text::Anchor,
22382        new_name: String,
22383        cx: &mut App,
22384    ) -> Option<Task<Result<ProjectTransaction>>>;
22385}
22386
22387pub trait CompletionProvider {
22388    fn completions(
22389        &self,
22390        excerpt_id: ExcerptId,
22391        buffer: &Entity<Buffer>,
22392        buffer_position: text::Anchor,
22393        trigger: CompletionContext,
22394        window: &mut Window,
22395        cx: &mut Context<Editor>,
22396    ) -> Task<Result<Vec<CompletionResponse>>>;
22397
22398    fn resolve_completions(
22399        &self,
22400        _buffer: Entity<Buffer>,
22401        _completion_indices: Vec<usize>,
22402        _completions: Rc<RefCell<Box<[Completion]>>>,
22403        _cx: &mut Context<Editor>,
22404    ) -> Task<Result<bool>> {
22405        Task::ready(Ok(false))
22406    }
22407
22408    fn apply_additional_edits_for_completion(
22409        &self,
22410        _buffer: Entity<Buffer>,
22411        _completions: Rc<RefCell<Box<[Completion]>>>,
22412        _completion_index: usize,
22413        _push_to_history: bool,
22414        _cx: &mut Context<Editor>,
22415    ) -> Task<Result<Option<language::Transaction>>> {
22416        Task::ready(Ok(None))
22417    }
22418
22419    fn is_completion_trigger(
22420        &self,
22421        buffer: &Entity<Buffer>,
22422        position: language::Anchor,
22423        text: &str,
22424        trigger_in_words: bool,
22425        menu_is_open: bool,
22426        cx: &mut Context<Editor>,
22427    ) -> bool;
22428
22429    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22430
22431    fn sort_completions(&self) -> bool {
22432        true
22433    }
22434
22435    fn filter_completions(&self) -> bool {
22436        true
22437    }
22438}
22439
22440pub trait CodeActionProvider {
22441    fn id(&self) -> Arc<str>;
22442
22443    fn code_actions(
22444        &self,
22445        buffer: &Entity<Buffer>,
22446        range: Range<text::Anchor>,
22447        window: &mut Window,
22448        cx: &mut App,
22449    ) -> Task<Result<Vec<CodeAction>>>;
22450
22451    fn apply_code_action(
22452        &self,
22453        buffer_handle: Entity<Buffer>,
22454        action: CodeAction,
22455        excerpt_id: ExcerptId,
22456        push_to_history: bool,
22457        window: &mut Window,
22458        cx: &mut App,
22459    ) -> Task<Result<ProjectTransaction>>;
22460}
22461
22462impl CodeActionProvider for Entity<Project> {
22463    fn id(&self) -> Arc<str> {
22464        "project".into()
22465    }
22466
22467    fn code_actions(
22468        &self,
22469        buffer: &Entity<Buffer>,
22470        range: Range<text::Anchor>,
22471        _window: &mut Window,
22472        cx: &mut App,
22473    ) -> Task<Result<Vec<CodeAction>>> {
22474        self.update(cx, |project, cx| {
22475            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22476            let code_actions = project.code_actions(buffer, range, None, cx);
22477            cx.background_spawn(async move {
22478                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22479                Ok(code_lens_actions
22480                    .context("code lens fetch")?
22481                    .into_iter()
22482                    .flatten()
22483                    .chain(
22484                        code_actions
22485                            .context("code action fetch")?
22486                            .into_iter()
22487                            .flatten(),
22488                    )
22489                    .collect())
22490            })
22491        })
22492    }
22493
22494    fn apply_code_action(
22495        &self,
22496        buffer_handle: Entity<Buffer>,
22497        action: CodeAction,
22498        _excerpt_id: ExcerptId,
22499        push_to_history: bool,
22500        _window: &mut Window,
22501        cx: &mut App,
22502    ) -> Task<Result<ProjectTransaction>> {
22503        self.update(cx, |project, cx| {
22504            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22505        })
22506    }
22507}
22508
22509fn snippet_completions(
22510    project: &Project,
22511    buffer: &Entity<Buffer>,
22512    buffer_position: text::Anchor,
22513    cx: &mut App,
22514) -> Task<Result<CompletionResponse>> {
22515    let languages = buffer.read(cx).languages_at(buffer_position);
22516    let snippet_store = project.snippets().read(cx);
22517
22518    let scopes: Vec<_> = languages
22519        .iter()
22520        .filter_map(|language| {
22521            let language_name = language.lsp_id();
22522            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22523
22524            if snippets.is_empty() {
22525                None
22526            } else {
22527                Some((language.default_scope(), snippets))
22528            }
22529        })
22530        .collect();
22531
22532    if scopes.is_empty() {
22533        return Task::ready(Ok(CompletionResponse {
22534            completions: vec![],
22535            display_options: CompletionDisplayOptions::default(),
22536            is_incomplete: false,
22537        }));
22538    }
22539
22540    let snapshot = buffer.read(cx).text_snapshot();
22541    let chars: String = snapshot
22542        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22543        .collect();
22544    let executor = cx.background_executor().clone();
22545
22546    cx.background_spawn(async move {
22547        let mut is_incomplete = false;
22548        let mut completions: Vec<Completion> = Vec::new();
22549        for (scope, snippets) in scopes.into_iter() {
22550            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22551            let mut last_word = chars
22552                .chars()
22553                .take_while(|c| classifier.is_word(*c))
22554                .collect::<String>();
22555            last_word = last_word.chars().rev().collect();
22556
22557            if last_word.is_empty() {
22558                return Ok(CompletionResponse {
22559                    completions: vec![],
22560                    display_options: CompletionDisplayOptions::default(),
22561                    is_incomplete: true,
22562                });
22563            }
22564
22565            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22566            let to_lsp = |point: &text::Anchor| {
22567                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22568                point_to_lsp(end)
22569            };
22570            let lsp_end = to_lsp(&buffer_position);
22571
22572            let candidates = snippets
22573                .iter()
22574                .enumerate()
22575                .flat_map(|(ix, snippet)| {
22576                    snippet
22577                        .prefix
22578                        .iter()
22579                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22580                })
22581                .collect::<Vec<StringMatchCandidate>>();
22582
22583            const MAX_RESULTS: usize = 100;
22584            let mut matches = fuzzy::match_strings(
22585                &candidates,
22586                &last_word,
22587                last_word.chars().any(|c| c.is_uppercase()),
22588                true,
22589                MAX_RESULTS,
22590                &Default::default(),
22591                executor.clone(),
22592            )
22593            .await;
22594
22595            if matches.len() >= MAX_RESULTS {
22596                is_incomplete = true;
22597            }
22598
22599            // Remove all candidates where the query's start does not match the start of any word in the candidate
22600            if let Some(query_start) = last_word.chars().next() {
22601                matches.retain(|string_match| {
22602                    split_words(&string_match.string).any(|word| {
22603                        // Check that the first codepoint of the word as lowercase matches the first
22604                        // codepoint of the query as lowercase
22605                        word.chars()
22606                            .flat_map(|codepoint| codepoint.to_lowercase())
22607                            .zip(query_start.to_lowercase())
22608                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22609                    })
22610                });
22611            }
22612
22613            let matched_strings = matches
22614                .into_iter()
22615                .map(|m| m.string)
22616                .collect::<HashSet<_>>();
22617
22618            completions.extend(snippets.iter().filter_map(|snippet| {
22619                let matching_prefix = snippet
22620                    .prefix
22621                    .iter()
22622                    .find(|prefix| matched_strings.contains(*prefix))?;
22623                let start = as_offset - last_word.len();
22624                let start = snapshot.anchor_before(start);
22625                let range = start..buffer_position;
22626                let lsp_start = to_lsp(&start);
22627                let lsp_range = lsp::Range {
22628                    start: lsp_start,
22629                    end: lsp_end,
22630                };
22631                Some(Completion {
22632                    replace_range: range,
22633                    new_text: snippet.body.clone(),
22634                    source: CompletionSource::Lsp {
22635                        insert_range: None,
22636                        server_id: LanguageServerId(usize::MAX),
22637                        resolved: true,
22638                        lsp_completion: Box::new(lsp::CompletionItem {
22639                            label: snippet.prefix.first().unwrap().clone(),
22640                            kind: Some(CompletionItemKind::SNIPPET),
22641                            label_details: snippet.description.as_ref().map(|description| {
22642                                lsp::CompletionItemLabelDetails {
22643                                    detail: Some(description.clone()),
22644                                    description: None,
22645                                }
22646                            }),
22647                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22648                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22649                                lsp::InsertReplaceEdit {
22650                                    new_text: snippet.body.clone(),
22651                                    insert: lsp_range,
22652                                    replace: lsp_range,
22653                                },
22654                            )),
22655                            filter_text: Some(snippet.body.clone()),
22656                            sort_text: Some(char::MAX.to_string()),
22657                            ..lsp::CompletionItem::default()
22658                        }),
22659                        lsp_defaults: None,
22660                    },
22661                    label: CodeLabel {
22662                        text: matching_prefix.clone(),
22663                        runs: Vec::new(),
22664                        filter_range: 0..matching_prefix.len(),
22665                    },
22666                    icon_path: None,
22667                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22668                        single_line: snippet.name.clone().into(),
22669                        plain_text: snippet
22670                            .description
22671                            .clone()
22672                            .map(|description| description.into()),
22673                    }),
22674                    insert_text_mode: None,
22675                    confirm: None,
22676                })
22677            }))
22678        }
22679
22680        Ok(CompletionResponse {
22681            completions,
22682            display_options: CompletionDisplayOptions::default(),
22683            is_incomplete,
22684        })
22685    })
22686}
22687
22688impl CompletionProvider for Entity<Project> {
22689    fn completions(
22690        &self,
22691        _excerpt_id: ExcerptId,
22692        buffer: &Entity<Buffer>,
22693        buffer_position: text::Anchor,
22694        options: CompletionContext,
22695        _window: &mut Window,
22696        cx: &mut Context<Editor>,
22697    ) -> Task<Result<Vec<CompletionResponse>>> {
22698        self.update(cx, |project, cx| {
22699            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22700            let project_completions = project.completions(buffer, buffer_position, options, cx);
22701            cx.background_spawn(async move {
22702                let mut responses = project_completions.await?;
22703                let snippets = snippets.await?;
22704                if !snippets.completions.is_empty() {
22705                    responses.push(snippets);
22706                }
22707                Ok(responses)
22708            })
22709        })
22710    }
22711
22712    fn resolve_completions(
22713        &self,
22714        buffer: Entity<Buffer>,
22715        completion_indices: Vec<usize>,
22716        completions: Rc<RefCell<Box<[Completion]>>>,
22717        cx: &mut Context<Editor>,
22718    ) -> Task<Result<bool>> {
22719        self.update(cx, |project, cx| {
22720            project.lsp_store().update(cx, |lsp_store, cx| {
22721                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22722            })
22723        })
22724    }
22725
22726    fn apply_additional_edits_for_completion(
22727        &self,
22728        buffer: Entity<Buffer>,
22729        completions: Rc<RefCell<Box<[Completion]>>>,
22730        completion_index: usize,
22731        push_to_history: bool,
22732        cx: &mut Context<Editor>,
22733    ) -> Task<Result<Option<language::Transaction>>> {
22734        self.update(cx, |project, cx| {
22735            project.lsp_store().update(cx, |lsp_store, cx| {
22736                lsp_store.apply_additional_edits_for_completion(
22737                    buffer,
22738                    completions,
22739                    completion_index,
22740                    push_to_history,
22741                    cx,
22742                )
22743            })
22744        })
22745    }
22746
22747    fn is_completion_trigger(
22748        &self,
22749        buffer: &Entity<Buffer>,
22750        position: language::Anchor,
22751        text: &str,
22752        trigger_in_words: bool,
22753        menu_is_open: bool,
22754        cx: &mut Context<Editor>,
22755    ) -> bool {
22756        let mut chars = text.chars();
22757        let char = if let Some(char) = chars.next() {
22758            char
22759        } else {
22760            return false;
22761        };
22762        if chars.next().is_some() {
22763            return false;
22764        }
22765
22766        let buffer = buffer.read(cx);
22767        let snapshot = buffer.snapshot();
22768        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22769            return false;
22770        }
22771        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22772        if trigger_in_words && classifier.is_word(char) {
22773            return true;
22774        }
22775
22776        buffer.completion_triggers().contains(text)
22777    }
22778}
22779
22780impl SemanticsProvider for Entity<Project> {
22781    fn hover(
22782        &self,
22783        buffer: &Entity<Buffer>,
22784        position: text::Anchor,
22785        cx: &mut App,
22786    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22787        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22788    }
22789
22790    fn document_highlights(
22791        &self,
22792        buffer: &Entity<Buffer>,
22793        position: text::Anchor,
22794        cx: &mut App,
22795    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22796        Some(self.update(cx, |project, cx| {
22797            project.document_highlights(buffer, position, cx)
22798        }))
22799    }
22800
22801    fn definitions(
22802        &self,
22803        buffer: &Entity<Buffer>,
22804        position: text::Anchor,
22805        kind: GotoDefinitionKind,
22806        cx: &mut App,
22807    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22808        Some(self.update(cx, |project, cx| match kind {
22809            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22810            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22811            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22812            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22813        }))
22814    }
22815
22816    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22817        self.update(cx, |project, cx| {
22818            if project
22819                .active_debug_session(cx)
22820                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22821            {
22822                return true;
22823            }
22824
22825            buffer.update(cx, |buffer, cx| {
22826                project.any_language_server_supports_inlay_hints(buffer, cx)
22827            })
22828        })
22829    }
22830
22831    fn inline_values(
22832        &self,
22833        buffer_handle: Entity<Buffer>,
22834        range: Range<text::Anchor>,
22835        cx: &mut App,
22836    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22837        self.update(cx, |project, cx| {
22838            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22839
22840            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22841        })
22842    }
22843
22844    fn inlay_hints(
22845        &self,
22846        buffer_handle: Entity<Buffer>,
22847        range: Range<text::Anchor>,
22848        cx: &mut App,
22849    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22850        Some(self.update(cx, |project, cx| {
22851            project.inlay_hints(buffer_handle, range, cx)
22852        }))
22853    }
22854
22855    fn resolve_inlay_hint(
22856        &self,
22857        hint: InlayHint,
22858        buffer_handle: Entity<Buffer>,
22859        server_id: LanguageServerId,
22860        cx: &mut App,
22861    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22862        Some(self.update(cx, |project, cx| {
22863            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22864        }))
22865    }
22866
22867    fn range_for_rename(
22868        &self,
22869        buffer: &Entity<Buffer>,
22870        position: text::Anchor,
22871        cx: &mut App,
22872    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22873        Some(self.update(cx, |project, cx| {
22874            let buffer = buffer.clone();
22875            let task = project.prepare_rename(buffer.clone(), position, cx);
22876            cx.spawn(async move |_, cx| {
22877                Ok(match task.await? {
22878                    PrepareRenameResponse::Success(range) => Some(range),
22879                    PrepareRenameResponse::InvalidPosition => None,
22880                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22881                        // Fallback on using TreeSitter info to determine identifier range
22882                        buffer.read_with(cx, |buffer, _| {
22883                            let snapshot = buffer.snapshot();
22884                            let (range, kind) = snapshot.surrounding_word(position, false);
22885                            if kind != Some(CharKind::Word) {
22886                                return None;
22887                            }
22888                            Some(
22889                                snapshot.anchor_before(range.start)
22890                                    ..snapshot.anchor_after(range.end),
22891                            )
22892                        })?
22893                    }
22894                })
22895            })
22896        }))
22897    }
22898
22899    fn perform_rename(
22900        &self,
22901        buffer: &Entity<Buffer>,
22902        position: text::Anchor,
22903        new_name: String,
22904        cx: &mut App,
22905    ) -> Option<Task<Result<ProjectTransaction>>> {
22906        Some(self.update(cx, |project, cx| {
22907            project.perform_rename(buffer.clone(), position, new_name, cx)
22908        }))
22909    }
22910}
22911
22912fn inlay_hint_settings(
22913    location: Anchor,
22914    snapshot: &MultiBufferSnapshot,
22915    cx: &mut Context<Editor>,
22916) -> InlayHintSettings {
22917    let file = snapshot.file_at(location);
22918    let language = snapshot.language_at(location).map(|l| l.name());
22919    language_settings(language, file, cx).inlay_hints
22920}
22921
22922fn consume_contiguous_rows(
22923    contiguous_row_selections: &mut Vec<Selection<Point>>,
22924    selection: &Selection<Point>,
22925    display_map: &DisplaySnapshot,
22926    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22927) -> (MultiBufferRow, MultiBufferRow) {
22928    contiguous_row_selections.push(selection.clone());
22929    let start_row = starting_row(selection, display_map);
22930    let mut end_row = ending_row(selection, display_map);
22931
22932    while let Some(next_selection) = selections.peek() {
22933        if next_selection.start.row <= end_row.0 {
22934            end_row = ending_row(next_selection, display_map);
22935            contiguous_row_selections.push(selections.next().unwrap().clone());
22936        } else {
22937            break;
22938        }
22939    }
22940    (start_row, end_row)
22941}
22942
22943fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22944    if selection.start.column > 0 {
22945        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22946    } else {
22947        MultiBufferRow(selection.start.row)
22948    }
22949}
22950
22951fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22952    if next_selection.end.column > 0 || next_selection.is_empty() {
22953        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22954    } else {
22955        MultiBufferRow(next_selection.end.row)
22956    }
22957}
22958
22959impl EditorSnapshot {
22960    pub fn remote_selections_in_range<'a>(
22961        &'a self,
22962        range: &'a Range<Anchor>,
22963        collaboration_hub: &dyn CollaborationHub,
22964        cx: &'a App,
22965    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22966        let participant_names = collaboration_hub.user_names(cx);
22967        let participant_indices = collaboration_hub.user_participant_indices(cx);
22968        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22969        let collaborators_by_replica_id = collaborators_by_peer_id
22970            .values()
22971            .map(|collaborator| (collaborator.replica_id, collaborator))
22972            .collect::<HashMap<_, _>>();
22973        self.buffer_snapshot
22974            .selections_in_range(range, false)
22975            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22976                if replica_id == AGENT_REPLICA_ID {
22977                    Some(RemoteSelection {
22978                        replica_id,
22979                        selection,
22980                        cursor_shape,
22981                        line_mode,
22982                        collaborator_id: CollaboratorId::Agent,
22983                        user_name: Some("Agent".into()),
22984                        color: cx.theme().players().agent(),
22985                    })
22986                } else {
22987                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22988                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22989                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22990                    Some(RemoteSelection {
22991                        replica_id,
22992                        selection,
22993                        cursor_shape,
22994                        line_mode,
22995                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22996                        user_name,
22997                        color: if let Some(index) = participant_index {
22998                            cx.theme().players().color_for_participant(index.0)
22999                        } else {
23000                            cx.theme().players().absent()
23001                        },
23002                    })
23003                }
23004            })
23005    }
23006
23007    pub fn hunks_for_ranges(
23008        &self,
23009        ranges: impl IntoIterator<Item = Range<Point>>,
23010    ) -> Vec<MultiBufferDiffHunk> {
23011        let mut hunks = Vec::new();
23012        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23013            HashMap::default();
23014        for query_range in ranges {
23015            let query_rows =
23016                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23017            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23018                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23019            ) {
23020                // Include deleted hunks that are adjacent to the query range, because
23021                // otherwise they would be missed.
23022                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23023                if hunk.status().is_deleted() {
23024                    intersects_range |= hunk.row_range.start == query_rows.end;
23025                    intersects_range |= hunk.row_range.end == query_rows.start;
23026                }
23027                if intersects_range {
23028                    if !processed_buffer_rows
23029                        .entry(hunk.buffer_id)
23030                        .or_default()
23031                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23032                    {
23033                        continue;
23034                    }
23035                    hunks.push(hunk);
23036                }
23037            }
23038        }
23039
23040        hunks
23041    }
23042
23043    fn display_diff_hunks_for_rows<'a>(
23044        &'a self,
23045        display_rows: Range<DisplayRow>,
23046        folded_buffers: &'a HashSet<BufferId>,
23047    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23048        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23049        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23050
23051        self.buffer_snapshot
23052            .diff_hunks_in_range(buffer_start..buffer_end)
23053            .filter_map(|hunk| {
23054                if folded_buffers.contains(&hunk.buffer_id) {
23055                    return None;
23056                }
23057
23058                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23059                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23060
23061                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23062                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23063
23064                let display_hunk = if hunk_display_start.column() != 0 {
23065                    DisplayDiffHunk::Folded {
23066                        display_row: hunk_display_start.row(),
23067                    }
23068                } else {
23069                    let mut end_row = hunk_display_end.row();
23070                    if hunk_display_end.column() > 0 {
23071                        end_row.0 += 1;
23072                    }
23073                    let is_created_file = hunk.is_created_file();
23074                    DisplayDiffHunk::Unfolded {
23075                        status: hunk.status(),
23076                        diff_base_byte_range: hunk.diff_base_byte_range,
23077                        display_row_range: hunk_display_start.row()..end_row,
23078                        multi_buffer_range: Anchor::range_in_buffer(
23079                            hunk.excerpt_id,
23080                            hunk.buffer_id,
23081                            hunk.buffer_range,
23082                        ),
23083                        is_created_file,
23084                    }
23085                };
23086
23087                Some(display_hunk)
23088            })
23089    }
23090
23091    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23092        self.display_snapshot.buffer_snapshot.language_at(position)
23093    }
23094
23095    pub fn is_focused(&self) -> bool {
23096        self.is_focused
23097    }
23098
23099    pub fn placeholder_text(&self) -> Option<String> {
23100        self.placeholder_display_snapshot
23101            .as_ref()
23102            .map(|display_map| display_map.text())
23103    }
23104
23105    pub fn scroll_position(&self) -> gpui::Point<f32> {
23106        self.scroll_anchor.scroll_position(&self.display_snapshot)
23107    }
23108
23109    fn gutter_dimensions(
23110        &self,
23111        font_id: FontId,
23112        font_size: Pixels,
23113        max_line_number_width: Pixels,
23114        cx: &App,
23115    ) -> Option<GutterDimensions> {
23116        if !self.show_gutter {
23117            return None;
23118        }
23119
23120        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23121        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23122
23123        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23124            matches!(
23125                ProjectSettings::get_global(cx).git.git_gutter,
23126                Some(GitGutterSetting::TrackedFiles)
23127            )
23128        });
23129        let gutter_settings = EditorSettings::get_global(cx).gutter;
23130        let show_line_numbers = self
23131            .show_line_numbers
23132            .unwrap_or(gutter_settings.line_numbers);
23133        let line_gutter_width = if show_line_numbers {
23134            // Avoid flicker-like gutter resizes when the line number gains another digit by
23135            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23136            let min_width_for_number_on_gutter =
23137                ch_advance * gutter_settings.min_line_number_digits as f32;
23138            max_line_number_width.max(min_width_for_number_on_gutter)
23139        } else {
23140            0.0.into()
23141        };
23142
23143        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23144        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23145
23146        let git_blame_entries_width =
23147            self.git_blame_gutter_max_author_length
23148                .map(|max_author_length| {
23149                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23150                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23151
23152                    /// The number of characters to dedicate to gaps and margins.
23153                    const SPACING_WIDTH: usize = 4;
23154
23155                    let max_char_count = max_author_length.min(renderer.max_author_length())
23156                        + ::git::SHORT_SHA_LENGTH
23157                        + MAX_RELATIVE_TIMESTAMP.len()
23158                        + SPACING_WIDTH;
23159
23160                    ch_advance * max_char_count
23161                });
23162
23163        let is_singleton = self.buffer_snapshot.is_singleton();
23164
23165        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23166        left_padding += if !is_singleton {
23167            ch_width * 4.0
23168        } else if show_runnables || show_breakpoints {
23169            ch_width * 3.0
23170        } else if show_git_gutter && show_line_numbers {
23171            ch_width * 2.0
23172        } else if show_git_gutter || show_line_numbers {
23173            ch_width
23174        } else {
23175            px(0.)
23176        };
23177
23178        let shows_folds = is_singleton && gutter_settings.folds;
23179
23180        let right_padding = if shows_folds && show_line_numbers {
23181            ch_width * 4.0
23182        } else if shows_folds || (!is_singleton && show_line_numbers) {
23183            ch_width * 3.0
23184        } else if show_line_numbers {
23185            ch_width
23186        } else {
23187            px(0.)
23188        };
23189
23190        Some(GutterDimensions {
23191            left_padding,
23192            right_padding,
23193            width: line_gutter_width + left_padding + right_padding,
23194            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23195            git_blame_entries_width,
23196        })
23197    }
23198
23199    pub fn render_crease_toggle(
23200        &self,
23201        buffer_row: MultiBufferRow,
23202        row_contains_cursor: bool,
23203        editor: Entity<Editor>,
23204        window: &mut Window,
23205        cx: &mut App,
23206    ) -> Option<AnyElement> {
23207        let folded = self.is_line_folded(buffer_row);
23208        let mut is_foldable = false;
23209
23210        if let Some(crease) = self
23211            .crease_snapshot
23212            .query_row(buffer_row, &self.buffer_snapshot)
23213        {
23214            is_foldable = true;
23215            match crease {
23216                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23217                    if let Some(render_toggle) = render_toggle {
23218                        let toggle_callback =
23219                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23220                                if folded {
23221                                    editor.update(cx, |editor, cx| {
23222                                        editor.fold_at(buffer_row, window, cx)
23223                                    });
23224                                } else {
23225                                    editor.update(cx, |editor, cx| {
23226                                        editor.unfold_at(buffer_row, window, cx)
23227                                    });
23228                                }
23229                            });
23230                        return Some((render_toggle)(
23231                            buffer_row,
23232                            folded,
23233                            toggle_callback,
23234                            window,
23235                            cx,
23236                        ));
23237                    }
23238                }
23239            }
23240        }
23241
23242        is_foldable |= self.starts_indent(buffer_row);
23243
23244        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23245            Some(
23246                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23247                    .toggle_state(folded)
23248                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23249                        if folded {
23250                            this.unfold_at(buffer_row, window, cx);
23251                        } else {
23252                            this.fold_at(buffer_row, window, cx);
23253                        }
23254                    }))
23255                    .into_any_element(),
23256            )
23257        } else {
23258            None
23259        }
23260    }
23261
23262    pub fn render_crease_trailer(
23263        &self,
23264        buffer_row: MultiBufferRow,
23265        window: &mut Window,
23266        cx: &mut App,
23267    ) -> Option<AnyElement> {
23268        let folded = self.is_line_folded(buffer_row);
23269        if let Crease::Inline { render_trailer, .. } = self
23270            .crease_snapshot
23271            .query_row(buffer_row, &self.buffer_snapshot)?
23272        {
23273            let render_trailer = render_trailer.as_ref()?;
23274            Some(render_trailer(buffer_row, folded, window, cx))
23275        } else {
23276            None
23277        }
23278    }
23279}
23280
23281impl Deref for EditorSnapshot {
23282    type Target = DisplaySnapshot;
23283
23284    fn deref(&self) -> &Self::Target {
23285        &self.display_snapshot
23286    }
23287}
23288
23289#[derive(Clone, Debug, PartialEq, Eq)]
23290pub enum EditorEvent {
23291    InputIgnored {
23292        text: Arc<str>,
23293    },
23294    InputHandled {
23295        utf16_range_to_replace: Option<Range<isize>>,
23296        text: Arc<str>,
23297    },
23298    ExcerptsAdded {
23299        buffer: Entity<Buffer>,
23300        predecessor: ExcerptId,
23301        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23302    },
23303    ExcerptsRemoved {
23304        ids: Vec<ExcerptId>,
23305        removed_buffer_ids: Vec<BufferId>,
23306    },
23307    BufferFoldToggled {
23308        ids: Vec<ExcerptId>,
23309        folded: bool,
23310    },
23311    ExcerptsEdited {
23312        ids: Vec<ExcerptId>,
23313    },
23314    ExcerptsExpanded {
23315        ids: Vec<ExcerptId>,
23316    },
23317    BufferEdited,
23318    Edited {
23319        transaction_id: clock::Lamport,
23320    },
23321    Reparsed(BufferId),
23322    Focused,
23323    FocusedIn,
23324    Blurred,
23325    DirtyChanged,
23326    Saved,
23327    TitleChanged,
23328    SelectionsChanged {
23329        local: bool,
23330    },
23331    ScrollPositionChanged {
23332        local: bool,
23333        autoscroll: bool,
23334    },
23335    TransactionUndone {
23336        transaction_id: clock::Lamport,
23337    },
23338    TransactionBegun {
23339        transaction_id: clock::Lamport,
23340    },
23341    CursorShapeChanged,
23342    BreadcrumbsChanged,
23343    PushedToNavHistory {
23344        anchor: Anchor,
23345        is_deactivate: bool,
23346    },
23347}
23348
23349impl EventEmitter<EditorEvent> for Editor {}
23350
23351impl Focusable for Editor {
23352    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23353        self.focus_handle.clone()
23354    }
23355}
23356
23357impl Render for Editor {
23358    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23359        let settings = ThemeSettings::get_global(cx);
23360
23361        let mut text_style = match self.mode {
23362            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23363                color: cx.theme().colors().editor_foreground,
23364                font_family: settings.ui_font.family.clone(),
23365                font_features: settings.ui_font.features.clone(),
23366                font_fallbacks: settings.ui_font.fallbacks.clone(),
23367                font_size: rems(0.875).into(),
23368                font_weight: settings.ui_font.weight,
23369                line_height: relative(settings.buffer_line_height.value()),
23370                ..Default::default()
23371            },
23372            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23373                color: cx.theme().colors().editor_foreground,
23374                font_family: settings.buffer_font.family.clone(),
23375                font_features: settings.buffer_font.features.clone(),
23376                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23377                font_size: settings.buffer_font_size(cx).into(),
23378                font_weight: settings.buffer_font.weight,
23379                line_height: relative(settings.buffer_line_height.value()),
23380                ..Default::default()
23381            },
23382        };
23383        if let Some(text_style_refinement) = &self.text_style_refinement {
23384            text_style.refine(text_style_refinement)
23385        }
23386
23387        let background = match self.mode {
23388            EditorMode::SingleLine => cx.theme().system().transparent,
23389            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23390            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23391            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23392        };
23393
23394        EditorElement::new(
23395            &cx.entity(),
23396            EditorStyle {
23397                background,
23398                border: cx.theme().colors().border,
23399                local_player: cx.theme().players().local(),
23400                text: text_style,
23401                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23402                syntax: cx.theme().syntax().clone(),
23403                status: cx.theme().status().clone(),
23404                inlay_hints_style: make_inlay_hints_style(cx),
23405                edit_prediction_styles: make_suggestion_styles(cx),
23406                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23407                show_underlines: self.diagnostics_enabled(),
23408            },
23409        )
23410    }
23411}
23412
23413impl EntityInputHandler for Editor {
23414    fn text_for_range(
23415        &mut self,
23416        range_utf16: Range<usize>,
23417        adjusted_range: &mut Option<Range<usize>>,
23418        _: &mut Window,
23419        cx: &mut Context<Self>,
23420    ) -> Option<String> {
23421        let snapshot = self.buffer.read(cx).read(cx);
23422        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23423        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23424        if (start.0..end.0) != range_utf16 {
23425            adjusted_range.replace(start.0..end.0);
23426        }
23427        Some(snapshot.text_for_range(start..end).collect())
23428    }
23429
23430    fn selected_text_range(
23431        &mut self,
23432        ignore_disabled_input: bool,
23433        _: &mut Window,
23434        cx: &mut Context<Self>,
23435    ) -> Option<UTF16Selection> {
23436        // Prevent the IME menu from appearing when holding down an alphabetic key
23437        // while input is disabled.
23438        if !ignore_disabled_input && !self.input_enabled {
23439            return None;
23440        }
23441
23442        let selection = self.selections.newest::<OffsetUtf16>(cx);
23443        let range = selection.range();
23444
23445        Some(UTF16Selection {
23446            range: range.start.0..range.end.0,
23447            reversed: selection.reversed,
23448        })
23449    }
23450
23451    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23452        let snapshot = self.buffer.read(cx).read(cx);
23453        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23454        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23455    }
23456
23457    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23458        self.clear_highlights::<InputComposition>(cx);
23459        self.ime_transaction.take();
23460    }
23461
23462    fn replace_text_in_range(
23463        &mut self,
23464        range_utf16: Option<Range<usize>>,
23465        text: &str,
23466        window: &mut Window,
23467        cx: &mut Context<Self>,
23468    ) {
23469        if !self.input_enabled {
23470            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23471            return;
23472        }
23473
23474        self.transact(window, cx, |this, window, cx| {
23475            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23476                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23477                Some(this.selection_replacement_ranges(range_utf16, cx))
23478            } else {
23479                this.marked_text_ranges(cx)
23480            };
23481
23482            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23483                let newest_selection_id = this.selections.newest_anchor().id;
23484                this.selections
23485                    .all::<OffsetUtf16>(cx)
23486                    .iter()
23487                    .zip(ranges_to_replace.iter())
23488                    .find_map(|(selection, range)| {
23489                        if selection.id == newest_selection_id {
23490                            Some(
23491                                (range.start.0 as isize - selection.head().0 as isize)
23492                                    ..(range.end.0 as isize - selection.head().0 as isize),
23493                            )
23494                        } else {
23495                            None
23496                        }
23497                    })
23498            });
23499
23500            cx.emit(EditorEvent::InputHandled {
23501                utf16_range_to_replace: range_to_replace,
23502                text: text.into(),
23503            });
23504
23505            if let Some(new_selected_ranges) = new_selected_ranges {
23506                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23507                    selections.select_ranges(new_selected_ranges)
23508                });
23509                this.backspace(&Default::default(), window, cx);
23510            }
23511
23512            this.handle_input(text, window, cx);
23513        });
23514
23515        if let Some(transaction) = self.ime_transaction {
23516            self.buffer.update(cx, |buffer, cx| {
23517                buffer.group_until_transaction(transaction, cx);
23518            });
23519        }
23520
23521        self.unmark_text(window, cx);
23522    }
23523
23524    fn replace_and_mark_text_in_range(
23525        &mut self,
23526        range_utf16: Option<Range<usize>>,
23527        text: &str,
23528        new_selected_range_utf16: Option<Range<usize>>,
23529        window: &mut Window,
23530        cx: &mut Context<Self>,
23531    ) {
23532        if !self.input_enabled {
23533            return;
23534        }
23535
23536        let transaction = self.transact(window, cx, |this, window, cx| {
23537            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23538                let snapshot = this.buffer.read(cx).read(cx);
23539                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23540                    for marked_range in &mut marked_ranges {
23541                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23542                        marked_range.start.0 += relative_range_utf16.start;
23543                        marked_range.start =
23544                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23545                        marked_range.end =
23546                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23547                    }
23548                }
23549                Some(marked_ranges)
23550            } else if let Some(range_utf16) = range_utf16 {
23551                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23552                Some(this.selection_replacement_ranges(range_utf16, cx))
23553            } else {
23554                None
23555            };
23556
23557            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23558                let newest_selection_id = this.selections.newest_anchor().id;
23559                this.selections
23560                    .all::<OffsetUtf16>(cx)
23561                    .iter()
23562                    .zip(ranges_to_replace.iter())
23563                    .find_map(|(selection, range)| {
23564                        if selection.id == newest_selection_id {
23565                            Some(
23566                                (range.start.0 as isize - selection.head().0 as isize)
23567                                    ..(range.end.0 as isize - selection.head().0 as isize),
23568                            )
23569                        } else {
23570                            None
23571                        }
23572                    })
23573            });
23574
23575            cx.emit(EditorEvent::InputHandled {
23576                utf16_range_to_replace: range_to_replace,
23577                text: text.into(),
23578            });
23579
23580            if let Some(ranges) = ranges_to_replace {
23581                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23582                    s.select_ranges(ranges)
23583                });
23584            }
23585
23586            let marked_ranges = {
23587                let snapshot = this.buffer.read(cx).read(cx);
23588                this.selections
23589                    .disjoint_anchors_arc()
23590                    .iter()
23591                    .map(|selection| {
23592                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23593                    })
23594                    .collect::<Vec<_>>()
23595            };
23596
23597            if text.is_empty() {
23598                this.unmark_text(window, cx);
23599            } else {
23600                this.highlight_text::<InputComposition>(
23601                    marked_ranges.clone(),
23602                    HighlightStyle {
23603                        underline: Some(UnderlineStyle {
23604                            thickness: px(1.),
23605                            color: None,
23606                            wavy: false,
23607                        }),
23608                        ..Default::default()
23609                    },
23610                    cx,
23611                );
23612            }
23613
23614            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23615            let use_autoclose = this.use_autoclose;
23616            let use_auto_surround = this.use_auto_surround;
23617            this.set_use_autoclose(false);
23618            this.set_use_auto_surround(false);
23619            this.handle_input(text, window, cx);
23620            this.set_use_autoclose(use_autoclose);
23621            this.set_use_auto_surround(use_auto_surround);
23622
23623            if let Some(new_selected_range) = new_selected_range_utf16 {
23624                let snapshot = this.buffer.read(cx).read(cx);
23625                let new_selected_ranges = marked_ranges
23626                    .into_iter()
23627                    .map(|marked_range| {
23628                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23629                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23630                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23631                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23632                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23633                    })
23634                    .collect::<Vec<_>>();
23635
23636                drop(snapshot);
23637                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23638                    selections.select_ranges(new_selected_ranges)
23639                });
23640            }
23641        });
23642
23643        self.ime_transaction = self.ime_transaction.or(transaction);
23644        if let Some(transaction) = self.ime_transaction {
23645            self.buffer.update(cx, |buffer, cx| {
23646                buffer.group_until_transaction(transaction, cx);
23647            });
23648        }
23649
23650        if self.text_highlights::<InputComposition>(cx).is_none() {
23651            self.ime_transaction.take();
23652        }
23653    }
23654
23655    fn bounds_for_range(
23656        &mut self,
23657        range_utf16: Range<usize>,
23658        element_bounds: gpui::Bounds<Pixels>,
23659        window: &mut Window,
23660        cx: &mut Context<Self>,
23661    ) -> Option<gpui::Bounds<Pixels>> {
23662        let text_layout_details = self.text_layout_details(window);
23663        let CharacterDimensions {
23664            em_width,
23665            em_advance,
23666            line_height,
23667        } = self.character_dimensions(window);
23668
23669        let snapshot = self.snapshot(window, cx);
23670        let scroll_position = snapshot.scroll_position();
23671        let scroll_left = scroll_position.x * em_advance;
23672
23673        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23674        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23675            + self.gutter_dimensions.full_width();
23676        let y = line_height * (start.row().as_f32() - scroll_position.y);
23677
23678        Some(Bounds {
23679            origin: element_bounds.origin + point(x, y),
23680            size: size(em_width, line_height),
23681        })
23682    }
23683
23684    fn character_index_for_point(
23685        &mut self,
23686        point: gpui::Point<Pixels>,
23687        _window: &mut Window,
23688        _cx: &mut Context<Self>,
23689    ) -> Option<usize> {
23690        let position_map = self.last_position_map.as_ref()?;
23691        if !position_map.text_hitbox.contains(&point) {
23692            return None;
23693        }
23694        let display_point = position_map.point_for_position(point).previous_valid;
23695        let anchor = position_map
23696            .snapshot
23697            .display_point_to_anchor(display_point, Bias::Left);
23698        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23699        Some(utf16_offset.0)
23700    }
23701}
23702
23703trait SelectionExt {
23704    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23705    fn spanned_rows(
23706        &self,
23707        include_end_if_at_line_start: bool,
23708        map: &DisplaySnapshot,
23709    ) -> Range<MultiBufferRow>;
23710}
23711
23712impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23713    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23714        let start = self
23715            .start
23716            .to_point(&map.buffer_snapshot)
23717            .to_display_point(map);
23718        let end = self
23719            .end
23720            .to_point(&map.buffer_snapshot)
23721            .to_display_point(map);
23722        if self.reversed {
23723            end..start
23724        } else {
23725            start..end
23726        }
23727    }
23728
23729    fn spanned_rows(
23730        &self,
23731        include_end_if_at_line_start: bool,
23732        map: &DisplaySnapshot,
23733    ) -> Range<MultiBufferRow> {
23734        let start = self.start.to_point(&map.buffer_snapshot);
23735        let mut end = self.end.to_point(&map.buffer_snapshot);
23736        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23737            end.row -= 1;
23738        }
23739
23740        let buffer_start = map.prev_line_boundary(start).0;
23741        let buffer_end = map.next_line_boundary(end).0;
23742        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23743    }
23744}
23745
23746impl<T: InvalidationRegion> InvalidationStack<T> {
23747    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23748    where
23749        S: Clone + ToOffset,
23750    {
23751        while let Some(region) = self.last() {
23752            let all_selections_inside_invalidation_ranges =
23753                if selections.len() == region.ranges().len() {
23754                    selections
23755                        .iter()
23756                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23757                        .all(|(selection, invalidation_range)| {
23758                            let head = selection.head().to_offset(buffer);
23759                            invalidation_range.start <= head && invalidation_range.end >= head
23760                        })
23761                } else {
23762                    false
23763                };
23764
23765            if all_selections_inside_invalidation_ranges {
23766                break;
23767            } else {
23768                self.pop();
23769            }
23770        }
23771    }
23772}
23773
23774impl<T> Default for InvalidationStack<T> {
23775    fn default() -> Self {
23776        Self(Default::default())
23777    }
23778}
23779
23780impl<T> Deref for InvalidationStack<T> {
23781    type Target = Vec<T>;
23782
23783    fn deref(&self) -> &Self::Target {
23784        &self.0
23785    }
23786}
23787
23788impl<T> DerefMut for InvalidationStack<T> {
23789    fn deref_mut(&mut self) -> &mut Self::Target {
23790        &mut self.0
23791    }
23792}
23793
23794impl InvalidationRegion for SnippetState {
23795    fn ranges(&self) -> &[Range<Anchor>] {
23796        &self.ranges[self.active_index]
23797    }
23798}
23799
23800fn edit_prediction_edit_text(
23801    current_snapshot: &BufferSnapshot,
23802    edits: &[(Range<Anchor>, String)],
23803    edit_preview: &EditPreview,
23804    include_deletions: bool,
23805    cx: &App,
23806) -> HighlightedText {
23807    let edits = edits
23808        .iter()
23809        .map(|(anchor, text)| {
23810            (
23811                anchor.start.text_anchor..anchor.end.text_anchor,
23812                text.clone(),
23813            )
23814        })
23815        .collect::<Vec<_>>();
23816
23817    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23818}
23819
23820fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23821    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23822    // Just show the raw edit text with basic styling
23823    let mut text = String::new();
23824    let mut highlights = Vec::new();
23825
23826    let insertion_highlight_style = HighlightStyle {
23827        color: Some(cx.theme().colors().text),
23828        ..Default::default()
23829    };
23830
23831    for (_, edit_text) in edits {
23832        let start_offset = text.len();
23833        text.push_str(edit_text);
23834        let end_offset = text.len();
23835
23836        if start_offset < end_offset {
23837            highlights.push((start_offset..end_offset, insertion_highlight_style));
23838        }
23839    }
23840
23841    HighlightedText {
23842        text: text.into(),
23843        highlights,
23844    }
23845}
23846
23847pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23848    match severity {
23849        lsp::DiagnosticSeverity::ERROR => colors.error,
23850        lsp::DiagnosticSeverity::WARNING => colors.warning,
23851        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23852        lsp::DiagnosticSeverity::HINT => colors.info,
23853        _ => colors.ignored,
23854    }
23855}
23856
23857pub fn styled_runs_for_code_label<'a>(
23858    label: &'a CodeLabel,
23859    syntax_theme: &'a theme::SyntaxTheme,
23860) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23861    let fade_out = HighlightStyle {
23862        fade_out: Some(0.35),
23863        ..Default::default()
23864    };
23865
23866    let mut prev_end = label.filter_range.end;
23867    label
23868        .runs
23869        .iter()
23870        .enumerate()
23871        .flat_map(move |(ix, (range, highlight_id))| {
23872            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23873                style
23874            } else {
23875                return Default::default();
23876            };
23877            let muted_style = style.highlight(fade_out);
23878
23879            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23880            if range.start >= label.filter_range.end {
23881                if range.start > prev_end {
23882                    runs.push((prev_end..range.start, fade_out));
23883                }
23884                runs.push((range.clone(), muted_style));
23885            } else if range.end <= label.filter_range.end {
23886                runs.push((range.clone(), style));
23887            } else {
23888                runs.push((range.start..label.filter_range.end, style));
23889                runs.push((label.filter_range.end..range.end, muted_style));
23890            }
23891            prev_end = cmp::max(prev_end, range.end);
23892
23893            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23894                runs.push((prev_end..label.text.len(), fade_out));
23895            }
23896
23897            runs
23898        })
23899}
23900
23901pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23902    let mut prev_index = 0;
23903    let mut prev_codepoint: Option<char> = None;
23904    text.char_indices()
23905        .chain([(text.len(), '\0')])
23906        .filter_map(move |(index, codepoint)| {
23907            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23908            let is_boundary = index == text.len()
23909                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23910                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23911            if is_boundary {
23912                let chunk = &text[prev_index..index];
23913                prev_index = index;
23914                Some(chunk)
23915            } else {
23916                None
23917            }
23918        })
23919}
23920
23921pub trait RangeToAnchorExt: Sized {
23922    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23923
23924    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23925        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23926        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23927    }
23928}
23929
23930impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23931    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23932        let start_offset = self.start.to_offset(snapshot);
23933        let end_offset = self.end.to_offset(snapshot);
23934        if start_offset == end_offset {
23935            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23936        } else {
23937            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23938        }
23939    }
23940}
23941
23942pub trait RowExt {
23943    fn as_f32(&self) -> f32;
23944
23945    fn next_row(&self) -> Self;
23946
23947    fn previous_row(&self) -> Self;
23948
23949    fn minus(&self, other: Self) -> u32;
23950}
23951
23952impl RowExt for DisplayRow {
23953    fn as_f32(&self) -> f32 {
23954        self.0 as f32
23955    }
23956
23957    fn next_row(&self) -> Self {
23958        Self(self.0 + 1)
23959    }
23960
23961    fn previous_row(&self) -> Self {
23962        Self(self.0.saturating_sub(1))
23963    }
23964
23965    fn minus(&self, other: Self) -> u32 {
23966        self.0 - other.0
23967    }
23968}
23969
23970impl RowExt for MultiBufferRow {
23971    fn as_f32(&self) -> f32 {
23972        self.0 as f32
23973    }
23974
23975    fn next_row(&self) -> Self {
23976        Self(self.0 + 1)
23977    }
23978
23979    fn previous_row(&self) -> Self {
23980        Self(self.0.saturating_sub(1))
23981    }
23982
23983    fn minus(&self, other: Self) -> u32 {
23984        self.0 - other.0
23985    }
23986}
23987
23988trait RowRangeExt {
23989    type Row;
23990
23991    fn len(&self) -> usize;
23992
23993    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23994}
23995
23996impl RowRangeExt for Range<MultiBufferRow> {
23997    type Row = MultiBufferRow;
23998
23999    fn len(&self) -> usize {
24000        (self.end.0 - self.start.0) as usize
24001    }
24002
24003    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24004        (self.start.0..self.end.0).map(MultiBufferRow)
24005    }
24006}
24007
24008impl RowRangeExt for Range<DisplayRow> {
24009    type Row = DisplayRow;
24010
24011    fn len(&self) -> usize {
24012        (self.end.0 - self.start.0) as usize
24013    }
24014
24015    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24016        (self.start.0..self.end.0).map(DisplayRow)
24017    }
24018}
24019
24020/// If select range has more than one line, we
24021/// just point the cursor to range.start.
24022fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24023    if range.start.row == range.end.row {
24024        range
24025    } else {
24026        range.start..range.start
24027    }
24028}
24029pub struct KillRing(ClipboardItem);
24030impl Global for KillRing {}
24031
24032const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24033
24034enum BreakpointPromptEditAction {
24035    Log,
24036    Condition,
24037    HitCondition,
24038}
24039
24040struct BreakpointPromptEditor {
24041    pub(crate) prompt: Entity<Editor>,
24042    editor: WeakEntity<Editor>,
24043    breakpoint_anchor: Anchor,
24044    breakpoint: Breakpoint,
24045    edit_action: BreakpointPromptEditAction,
24046    block_ids: HashSet<CustomBlockId>,
24047    editor_margins: Arc<Mutex<EditorMargins>>,
24048    _subscriptions: Vec<Subscription>,
24049}
24050
24051impl BreakpointPromptEditor {
24052    const MAX_LINES: u8 = 4;
24053
24054    fn new(
24055        editor: WeakEntity<Editor>,
24056        breakpoint_anchor: Anchor,
24057        breakpoint: Breakpoint,
24058        edit_action: BreakpointPromptEditAction,
24059        window: &mut Window,
24060        cx: &mut Context<Self>,
24061    ) -> Self {
24062        let base_text = match edit_action {
24063            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24064            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24065            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24066        }
24067        .map(|msg| msg.to_string())
24068        .unwrap_or_default();
24069
24070        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24071        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24072
24073        let prompt = cx.new(|cx| {
24074            let mut prompt = Editor::new(
24075                EditorMode::AutoHeight {
24076                    min_lines: 1,
24077                    max_lines: Some(Self::MAX_LINES as usize),
24078                },
24079                buffer,
24080                None,
24081                window,
24082                cx,
24083            );
24084            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24085            prompt.set_show_cursor_when_unfocused(false, cx);
24086            prompt.set_placeholder_text(
24087                match edit_action {
24088                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24089                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24090                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24091                },
24092                window,
24093                cx,
24094            );
24095
24096            prompt
24097        });
24098
24099        Self {
24100            prompt,
24101            editor,
24102            breakpoint_anchor,
24103            breakpoint,
24104            edit_action,
24105            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24106            block_ids: Default::default(),
24107            _subscriptions: vec![],
24108        }
24109    }
24110
24111    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24112        self.block_ids.extend(block_ids)
24113    }
24114
24115    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24116        if let Some(editor) = self.editor.upgrade() {
24117            let message = self
24118                .prompt
24119                .read(cx)
24120                .buffer
24121                .read(cx)
24122                .as_singleton()
24123                .expect("A multi buffer in breakpoint prompt isn't possible")
24124                .read(cx)
24125                .as_rope()
24126                .to_string();
24127
24128            editor.update(cx, |editor, cx| {
24129                editor.edit_breakpoint_at_anchor(
24130                    self.breakpoint_anchor,
24131                    self.breakpoint.clone(),
24132                    match self.edit_action {
24133                        BreakpointPromptEditAction::Log => {
24134                            BreakpointEditAction::EditLogMessage(message.into())
24135                        }
24136                        BreakpointPromptEditAction::Condition => {
24137                            BreakpointEditAction::EditCondition(message.into())
24138                        }
24139                        BreakpointPromptEditAction::HitCondition => {
24140                            BreakpointEditAction::EditHitCondition(message.into())
24141                        }
24142                    },
24143                    cx,
24144                );
24145
24146                editor.remove_blocks(self.block_ids.clone(), None, cx);
24147                cx.focus_self(window);
24148            });
24149        }
24150    }
24151
24152    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24153        self.editor
24154            .update(cx, |editor, cx| {
24155                editor.remove_blocks(self.block_ids.clone(), None, cx);
24156                window.focus(&editor.focus_handle);
24157            })
24158            .log_err();
24159    }
24160
24161    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24162        let settings = ThemeSettings::get_global(cx);
24163        let text_style = TextStyle {
24164            color: if self.prompt.read(cx).read_only(cx) {
24165                cx.theme().colors().text_disabled
24166            } else {
24167                cx.theme().colors().text
24168            },
24169            font_family: settings.buffer_font.family.clone(),
24170            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24171            font_size: settings.buffer_font_size(cx).into(),
24172            font_weight: settings.buffer_font.weight,
24173            line_height: relative(settings.buffer_line_height.value()),
24174            ..Default::default()
24175        };
24176        EditorElement::new(
24177            &self.prompt,
24178            EditorStyle {
24179                background: cx.theme().colors().editor_background,
24180                local_player: cx.theme().players().local(),
24181                text: text_style,
24182                ..Default::default()
24183            },
24184        )
24185    }
24186}
24187
24188impl Render for BreakpointPromptEditor {
24189    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24190        let editor_margins = *self.editor_margins.lock();
24191        let gutter_dimensions = editor_margins.gutter;
24192        h_flex()
24193            .key_context("Editor")
24194            .bg(cx.theme().colors().editor_background)
24195            .border_y_1()
24196            .border_color(cx.theme().status().info_border)
24197            .size_full()
24198            .py(window.line_height() / 2.5)
24199            .on_action(cx.listener(Self::confirm))
24200            .on_action(cx.listener(Self::cancel))
24201            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24202            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24203    }
24204}
24205
24206impl Focusable for BreakpointPromptEditor {
24207    fn focus_handle(&self, cx: &App) -> FocusHandle {
24208        self.prompt.focus_handle(cx)
24209    }
24210}
24211
24212fn all_edits_insertions_or_deletions(
24213    edits: &Vec<(Range<Anchor>, String)>,
24214    snapshot: &MultiBufferSnapshot,
24215) -> bool {
24216    let mut all_insertions = true;
24217    let mut all_deletions = true;
24218
24219    for (range, new_text) in edits.iter() {
24220        let range_is_empty = range.to_offset(snapshot).is_empty();
24221        let text_is_empty = new_text.is_empty();
24222
24223        if range_is_empty != text_is_empty {
24224            if range_is_empty {
24225                all_deletions = false;
24226            } else {
24227                all_insertions = false;
24228            }
24229        } else {
24230            return false;
24231        }
24232
24233        if !all_insertions && !all_deletions {
24234            return false;
24235        }
24236    }
24237    all_insertions || all_deletions
24238}
24239
24240struct MissingEditPredictionKeybindingTooltip;
24241
24242impl Render for MissingEditPredictionKeybindingTooltip {
24243    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24244        ui::tooltip_container(window, cx, |container, _, cx| {
24245            container
24246                .flex_shrink_0()
24247                .max_w_80()
24248                .min_h(rems_from_px(124.))
24249                .justify_between()
24250                .child(
24251                    v_flex()
24252                        .flex_1()
24253                        .text_ui_sm(cx)
24254                        .child(Label::new("Conflict with Accept Keybinding"))
24255                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24256                )
24257                .child(
24258                    h_flex()
24259                        .pb_1()
24260                        .gap_1()
24261                        .items_end()
24262                        .w_full()
24263                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24264                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24265                        }))
24266                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24267                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24268                        })),
24269                )
24270        })
24271    }
24272}
24273
24274#[derive(Debug, Clone, Copy, PartialEq)]
24275pub struct LineHighlight {
24276    pub background: Background,
24277    pub border: Option<gpui::Hsla>,
24278    pub include_gutter: bool,
24279    pub type_id: Option<TypeId>,
24280}
24281
24282struct LineManipulationResult {
24283    pub new_text: String,
24284    pub line_count_before: usize,
24285    pub line_count_after: usize,
24286}
24287
24288fn render_diff_hunk_controls(
24289    row: u32,
24290    status: &DiffHunkStatus,
24291    hunk_range: Range<Anchor>,
24292    is_created_file: bool,
24293    line_height: Pixels,
24294    editor: &Entity<Editor>,
24295    _window: &mut Window,
24296    cx: &mut App,
24297) -> AnyElement {
24298    h_flex()
24299        .h(line_height)
24300        .mr_1()
24301        .gap_1()
24302        .px_0p5()
24303        .pb_1()
24304        .border_x_1()
24305        .border_b_1()
24306        .border_color(cx.theme().colors().border_variant)
24307        .rounded_b_lg()
24308        .bg(cx.theme().colors().editor_background)
24309        .gap_1()
24310        .block_mouse_except_scroll()
24311        .shadow_md()
24312        .child(if status.has_secondary_hunk() {
24313            Button::new(("stage", row as u64), "Stage")
24314                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24315                .tooltip({
24316                    let focus_handle = editor.focus_handle(cx);
24317                    move |window, cx| {
24318                        Tooltip::for_action_in(
24319                            "Stage Hunk",
24320                            &::git::ToggleStaged,
24321                            &focus_handle,
24322                            window,
24323                            cx,
24324                        )
24325                    }
24326                })
24327                .on_click({
24328                    let editor = editor.clone();
24329                    move |_event, _window, cx| {
24330                        editor.update(cx, |editor, cx| {
24331                            editor.stage_or_unstage_diff_hunks(
24332                                true,
24333                                vec![hunk_range.start..hunk_range.start],
24334                                cx,
24335                            );
24336                        });
24337                    }
24338                })
24339        } else {
24340            Button::new(("unstage", row as u64), "Unstage")
24341                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24342                .tooltip({
24343                    let focus_handle = editor.focus_handle(cx);
24344                    move |window, cx| {
24345                        Tooltip::for_action_in(
24346                            "Unstage Hunk",
24347                            &::git::ToggleStaged,
24348                            &focus_handle,
24349                            window,
24350                            cx,
24351                        )
24352                    }
24353                })
24354                .on_click({
24355                    let editor = editor.clone();
24356                    move |_event, _window, cx| {
24357                        editor.update(cx, |editor, cx| {
24358                            editor.stage_or_unstage_diff_hunks(
24359                                false,
24360                                vec![hunk_range.start..hunk_range.start],
24361                                cx,
24362                            );
24363                        });
24364                    }
24365                })
24366        })
24367        .child(
24368            Button::new(("restore", row as u64), "Restore")
24369                .tooltip({
24370                    let focus_handle = editor.focus_handle(cx);
24371                    move |window, cx| {
24372                        Tooltip::for_action_in(
24373                            "Restore Hunk",
24374                            &::git::Restore,
24375                            &focus_handle,
24376                            window,
24377                            cx,
24378                        )
24379                    }
24380                })
24381                .on_click({
24382                    let editor = editor.clone();
24383                    move |_event, window, cx| {
24384                        editor.update(cx, |editor, cx| {
24385                            let snapshot = editor.snapshot(window, cx);
24386                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24387                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24388                        });
24389                    }
24390                })
24391                .disabled(is_created_file),
24392        )
24393        .when(
24394            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24395            |el| {
24396                el.child(
24397                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24398                        .shape(IconButtonShape::Square)
24399                        .icon_size(IconSize::Small)
24400                        // .disabled(!has_multiple_hunks)
24401                        .tooltip({
24402                            let focus_handle = editor.focus_handle(cx);
24403                            move |window, cx| {
24404                                Tooltip::for_action_in(
24405                                    "Next Hunk",
24406                                    &GoToHunk,
24407                                    &focus_handle,
24408                                    window,
24409                                    cx,
24410                                )
24411                            }
24412                        })
24413                        .on_click({
24414                            let editor = editor.clone();
24415                            move |_event, window, cx| {
24416                                editor.update(cx, |editor, cx| {
24417                                    let snapshot = editor.snapshot(window, cx);
24418                                    let position =
24419                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24420                                    editor.go_to_hunk_before_or_after_position(
24421                                        &snapshot,
24422                                        position,
24423                                        Direction::Next,
24424                                        window,
24425                                        cx,
24426                                    );
24427                                    editor.expand_selected_diff_hunks(cx);
24428                                });
24429                            }
24430                        }),
24431                )
24432                .child(
24433                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24434                        .shape(IconButtonShape::Square)
24435                        .icon_size(IconSize::Small)
24436                        // .disabled(!has_multiple_hunks)
24437                        .tooltip({
24438                            let focus_handle = editor.focus_handle(cx);
24439                            move |window, cx| {
24440                                Tooltip::for_action_in(
24441                                    "Previous Hunk",
24442                                    &GoToPreviousHunk,
24443                                    &focus_handle,
24444                                    window,
24445                                    cx,
24446                                )
24447                            }
24448                        })
24449                        .on_click({
24450                            let editor = editor.clone();
24451                            move |_event, window, cx| {
24452                                editor.update(cx, |editor, cx| {
24453                                    let snapshot = editor.snapshot(window, cx);
24454                                    let point =
24455                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24456                                    editor.go_to_hunk_before_or_after_position(
24457                                        &snapshot,
24458                                        point,
24459                                        Direction::Prev,
24460                                        window,
24461                                        cx,
24462                                    );
24463                                    editor.expand_selected_diff_hunks(cx);
24464                                });
24465                            }
24466                        }),
24467                )
24468            },
24469        )
24470        .into_any_element()
24471}
24472
24473pub fn multibuffer_context_lines(cx: &App) -> u32 {
24474    EditorSettings::try_get(cx)
24475        .map(|settings| settings.excerpt_context_lines)
24476        .unwrap_or(2)
24477        .min(32)
24478}