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
 2418            .as_ref()
 2419            .is_some_and(|pending_selection| {
 2420                let snapshot = self.buffer().read(cx).snapshot(cx);
 2421                pending_selection
 2422                    .selection
 2423                    .range()
 2424                    .includes(range, &snapshot)
 2425            })
 2426        {
 2427            return true;
 2428        }
 2429
 2430        self.selections
 2431            .disjoint_in_range::<usize>(range.clone(), cx)
 2432            .into_iter()
 2433            .any(|selection| {
 2434                // This is needed to cover a corner case, if we just check for an existing
 2435                // selection in the fold range, having a cursor at the start of the fold
 2436                // marks it as selected. Non-empty selections don't cause this.
 2437                let length = selection.end - selection.start;
 2438                length > 0
 2439            })
 2440    }
 2441
 2442    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2443        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2444    }
 2445
 2446    fn key_context_internal(
 2447        &self,
 2448        has_active_edit_prediction: bool,
 2449        window: &Window,
 2450        cx: &App,
 2451    ) -> KeyContext {
 2452        let mut key_context = KeyContext::new_with_defaults();
 2453        key_context.add("Editor");
 2454        let mode = match self.mode {
 2455            EditorMode::SingleLine => "single_line",
 2456            EditorMode::AutoHeight { .. } => "auto_height",
 2457            EditorMode::Minimap { .. } => "minimap",
 2458            EditorMode::Full { .. } => "full",
 2459        };
 2460
 2461        if EditorSettings::jupyter_enabled(cx) {
 2462            key_context.add("jupyter");
 2463        }
 2464
 2465        key_context.set("mode", mode);
 2466        if self.pending_rename.is_some() {
 2467            key_context.add("renaming");
 2468        }
 2469
 2470        match self.context_menu.borrow().as_ref() {
 2471            Some(CodeContextMenu::Completions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_completions");
 2475                }
 2476            }
 2477            Some(CodeContextMenu::CodeActions(menu)) => {
 2478                if menu.visible() {
 2479                    key_context.add("menu");
 2480                    key_context.add("showing_code_actions")
 2481                }
 2482            }
 2483            None => {}
 2484        }
 2485
 2486        if self.signature_help_state.has_multiple_signatures() {
 2487            key_context.add("showing_signature_help");
 2488        }
 2489
 2490        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2491        if !self.focus_handle(cx).contains_focused(window, cx)
 2492            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2493        {
 2494            for addon in self.addons.values() {
 2495                addon.extend_key_context(&mut key_context, cx)
 2496            }
 2497        }
 2498
 2499        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2500            if let Some(extension) = singleton_buffer
 2501                .read(cx)
 2502                .file()
 2503                .and_then(|file| file.path().extension()?.to_str())
 2504            {
 2505                key_context.set("extension", extension.to_string());
 2506            }
 2507        } else {
 2508            key_context.add("multibuffer");
 2509        }
 2510
 2511        if has_active_edit_prediction {
 2512            if self.edit_prediction_in_conflict() {
 2513                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2514            } else {
 2515                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2516                key_context.add("copilot_suggestion");
 2517            }
 2518        }
 2519
 2520        if self.selection_mark_mode {
 2521            key_context.add("selection_mode");
 2522        }
 2523
 2524        key_context
 2525    }
 2526
 2527    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2528        if self.mouse_cursor_hidden {
 2529            self.mouse_cursor_hidden = false;
 2530            cx.notify();
 2531        }
 2532    }
 2533
 2534    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2535        let hide_mouse_cursor = match origin {
 2536            HideMouseCursorOrigin::TypingAction => {
 2537                matches!(
 2538                    self.hide_mouse_mode,
 2539                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2540                )
 2541            }
 2542            HideMouseCursorOrigin::MovementAction => {
 2543                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2544            }
 2545        };
 2546        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2547            self.mouse_cursor_hidden = hide_mouse_cursor;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn edit_prediction_in_conflict(&self) -> bool {
 2553        if !self.show_edit_predictions_in_menu() {
 2554            return false;
 2555        }
 2556
 2557        let showing_completions = self
 2558            .context_menu
 2559            .borrow()
 2560            .as_ref()
 2561            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2562
 2563        showing_completions
 2564            || self.edit_prediction_requires_modifier()
 2565            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2566            // bindings to insert tab characters.
 2567            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2568    }
 2569
 2570    pub fn accept_edit_prediction_keybind(
 2571        &self,
 2572        accept_partial: bool,
 2573        window: &Window,
 2574        cx: &App,
 2575    ) -> AcceptEditPredictionBinding {
 2576        let key_context = self.key_context_internal(true, window, cx);
 2577        let in_conflict = self.edit_prediction_in_conflict();
 2578
 2579        let bindings = if accept_partial {
 2580            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2581        } else {
 2582            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2583        };
 2584
 2585        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2586        // just the first one.
 2587        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2588            !in_conflict
 2589                || binding
 2590                    .keystrokes()
 2591                    .first()
 2592                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2593        }))
 2594    }
 2595
 2596    pub fn new_file(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFile,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2603            "Failed to create buffer",
 2604            window,
 2605            cx,
 2606            |e, _, _| match e.error_code() {
 2607                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2608                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2609                e.error_tag("required").unwrap_or("the latest version")
 2610            )),
 2611                _ => None,
 2612            },
 2613        );
 2614    }
 2615
 2616    pub fn new_in_workspace(
 2617        workspace: &mut Workspace,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) -> Task<Result<Entity<Editor>>> {
 2621        let project = workspace.project().clone();
 2622        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2623
 2624        cx.spawn_in(window, async move |workspace, cx| {
 2625            let buffer = create.await?;
 2626            workspace.update_in(cx, |workspace, window, cx| {
 2627                let editor =
 2628                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2629                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2630                editor
 2631            })
 2632        })
 2633    }
 2634
 2635    fn new_file_vertical(
 2636        workspace: &mut Workspace,
 2637        _: &workspace::NewFileSplitVertical,
 2638        window: &mut Window,
 2639        cx: &mut Context<Workspace>,
 2640    ) {
 2641        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2642    }
 2643
 2644    fn new_file_horizontal(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitHorizontal,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_in_direction(
 2654        workspace: &mut Workspace,
 2655        direction: SplitDirection,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        let project = workspace.project().clone();
 2660        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2661
 2662        cx.spawn_in(window, async move |workspace, cx| {
 2663            let buffer = create.await?;
 2664            workspace.update_in(cx, move |workspace, window, cx| {
 2665                workspace.split_item(
 2666                    direction,
 2667                    Box::new(
 2668                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2669                    ),
 2670                    window,
 2671                    cx,
 2672                )
 2673            })?;
 2674            anyhow::Ok(())
 2675        })
 2676        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2677            match e.error_code() {
 2678                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2679                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2680                e.error_tag("required").unwrap_or("the latest version")
 2681            )),
 2682                _ => None,
 2683            }
 2684        });
 2685    }
 2686
 2687    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2688        self.leader_id
 2689    }
 2690
 2691    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2692        &self.buffer
 2693    }
 2694
 2695    pub fn project(&self) -> Option<&Entity<Project>> {
 2696        self.project.as_ref()
 2697    }
 2698
 2699    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2700        self.workspace.as_ref()?.0.upgrade()
 2701    }
 2702
 2703    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2704        self.buffer().read(cx).title(cx)
 2705    }
 2706
 2707    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2708        let git_blame_gutter_max_author_length = self
 2709            .render_git_blame_gutter(cx)
 2710            .then(|| {
 2711                if let Some(blame) = self.blame.as_ref() {
 2712                    let max_author_length =
 2713                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2714                    Some(max_author_length)
 2715                } else {
 2716                    None
 2717                }
 2718            })
 2719            .flatten();
 2720
 2721        EditorSnapshot {
 2722            mode: self.mode.clone(),
 2723            show_gutter: self.show_gutter,
 2724            show_line_numbers: self.show_line_numbers,
 2725            show_git_diff_gutter: self.show_git_diff_gutter,
 2726            show_code_actions: self.show_code_actions,
 2727            show_runnables: self.show_runnables,
 2728            show_breakpoints: self.show_breakpoints,
 2729            git_blame_gutter_max_author_length,
 2730            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2731            placeholder_display_snapshot: self
 2732                .placeholder_display_map
 2733                .as_ref()
 2734                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2735            scroll_anchor: self.scroll_manager.anchor(),
 2736            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2737            is_focused: self.focus_handle.is_focused(window),
 2738            current_line_highlight: self
 2739                .current_line_highlight
 2740                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2741            gutter_hovered: self.gutter_hovered,
 2742        }
 2743    }
 2744
 2745    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2746        self.buffer.read(cx).language_at(point, cx)
 2747    }
 2748
 2749    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2750        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2751    }
 2752
 2753    pub fn active_excerpt(
 2754        &self,
 2755        cx: &App,
 2756    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2757        self.buffer
 2758            .read(cx)
 2759            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2760    }
 2761
 2762    pub fn mode(&self) -> &EditorMode {
 2763        &self.mode
 2764    }
 2765
 2766    pub fn set_mode(&mut self, mode: EditorMode) {
 2767        self.mode = mode;
 2768    }
 2769
 2770    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2771        self.collaboration_hub.as_deref()
 2772    }
 2773
 2774    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2775        self.collaboration_hub = Some(hub);
 2776    }
 2777
 2778    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2779        self.in_project_search = in_project_search;
 2780    }
 2781
 2782    pub fn set_custom_context_menu(
 2783        &mut self,
 2784        f: impl 'static
 2785        + Fn(
 2786            &mut Self,
 2787            DisplayPoint,
 2788            &mut Window,
 2789            &mut Context<Self>,
 2790        ) -> Option<Entity<ui::ContextMenu>>,
 2791    ) {
 2792        self.custom_context_menu = Some(Box::new(f))
 2793    }
 2794
 2795    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2796        self.completion_provider = provider;
 2797    }
 2798
 2799    #[cfg(any(test, feature = "test-support"))]
 2800    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2801        self.completion_provider.clone()
 2802    }
 2803
 2804    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2805        self.semantics_provider.clone()
 2806    }
 2807
 2808    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2809        self.semantics_provider = provider;
 2810    }
 2811
 2812    pub fn set_edit_prediction_provider<T>(
 2813        &mut self,
 2814        provider: Option<Entity<T>>,
 2815        window: &mut Window,
 2816        cx: &mut Context<Self>,
 2817    ) where
 2818        T: EditPredictionProvider,
 2819    {
 2820        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2821            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2822                if this.focus_handle.is_focused(window) {
 2823                    this.update_visible_edit_prediction(window, cx);
 2824                }
 2825            }),
 2826            provider: Arc::new(provider),
 2827        });
 2828        self.update_edit_prediction_settings(cx);
 2829        self.refresh_edit_prediction(false, false, window, cx);
 2830    }
 2831
 2832    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2833        self.placeholder_display_map
 2834            .as_ref()
 2835            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2836    }
 2837
 2838    pub fn set_placeholder_text(
 2839        &mut self,
 2840        placeholder_text: &str,
 2841        window: &mut Window,
 2842        cx: &mut Context<Self>,
 2843    ) {
 2844        let multibuffer = cx
 2845            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2846
 2847        let style = window.text_style();
 2848
 2849        self.placeholder_display_map = Some(cx.new(|cx| {
 2850            DisplayMap::new(
 2851                multibuffer,
 2852                style.font(),
 2853                style.font_size.to_pixels(window.rem_size()),
 2854                None,
 2855                FILE_HEADER_HEIGHT,
 2856                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2857                Default::default(),
 2858                DiagnosticSeverity::Off,
 2859                cx,
 2860            )
 2861        }));
 2862        cx.notify();
 2863    }
 2864
 2865    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2866        self.cursor_shape = cursor_shape;
 2867
 2868        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2869        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2870
 2871        cx.notify();
 2872    }
 2873
 2874    pub fn set_current_line_highlight(
 2875        &mut self,
 2876        current_line_highlight: Option<CurrentLineHighlight>,
 2877    ) {
 2878        self.current_line_highlight = current_line_highlight;
 2879    }
 2880
 2881    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2882        self.collapse_matches = collapse_matches;
 2883    }
 2884
 2885    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2886        let buffers = self.buffer.read(cx).all_buffers();
 2887        let Some(project) = self.project.as_ref() else {
 2888            return;
 2889        };
 2890        project.update(cx, |project, cx| {
 2891            for buffer in buffers {
 2892                self.registered_buffers
 2893                    .entry(buffer.read(cx).remote_id())
 2894                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2895            }
 2896        })
 2897    }
 2898
 2899    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2900        if self.collapse_matches {
 2901            return range.start..range.start;
 2902        }
 2903        range.clone()
 2904    }
 2905
 2906    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2907        if self.display_map.read(cx).clip_at_line_ends != clip {
 2908            self.display_map
 2909                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2910        }
 2911    }
 2912
 2913    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2914        self.input_enabled = input_enabled;
 2915    }
 2916
 2917    pub fn set_edit_predictions_hidden_for_vim_mode(
 2918        &mut self,
 2919        hidden: bool,
 2920        window: &mut Window,
 2921        cx: &mut Context<Self>,
 2922    ) {
 2923        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2924            self.edit_predictions_hidden_for_vim_mode = hidden;
 2925            if hidden {
 2926                self.update_visible_edit_prediction(window, cx);
 2927            } else {
 2928                self.refresh_edit_prediction(true, false, window, cx);
 2929            }
 2930        }
 2931    }
 2932
 2933    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2934        self.menu_edit_predictions_policy = value;
 2935    }
 2936
 2937    pub fn set_autoindent(&mut self, autoindent: bool) {
 2938        if autoindent {
 2939            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2940        } else {
 2941            self.autoindent_mode = None;
 2942        }
 2943    }
 2944
 2945    pub fn read_only(&self, cx: &App) -> bool {
 2946        self.read_only || self.buffer.read(cx).read_only()
 2947    }
 2948
 2949    pub fn set_read_only(&mut self, read_only: bool) {
 2950        self.read_only = read_only;
 2951    }
 2952
 2953    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2954        self.use_autoclose = autoclose;
 2955    }
 2956
 2957    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2958        self.use_auto_surround = auto_surround;
 2959    }
 2960
 2961    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2962        self.auto_replace_emoji_shortcode = auto_replace;
 2963    }
 2964
 2965    pub fn toggle_edit_predictions(
 2966        &mut self,
 2967        _: &ToggleEditPrediction,
 2968        window: &mut Window,
 2969        cx: &mut Context<Self>,
 2970    ) {
 2971        if self.show_edit_predictions_override.is_some() {
 2972            self.set_show_edit_predictions(None, window, cx);
 2973        } else {
 2974            let show_edit_predictions = !self.edit_predictions_enabled();
 2975            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2976        }
 2977    }
 2978
 2979    pub fn set_show_edit_predictions(
 2980        &mut self,
 2981        show_edit_predictions: Option<bool>,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984    ) {
 2985        self.show_edit_predictions_override = show_edit_predictions;
 2986        self.update_edit_prediction_settings(cx);
 2987
 2988        if let Some(false) = show_edit_predictions {
 2989            self.discard_edit_prediction(false, cx);
 2990        } else {
 2991            self.refresh_edit_prediction(false, true, window, cx);
 2992        }
 2993    }
 2994
 2995    fn edit_predictions_disabled_in_scope(
 2996        &self,
 2997        buffer: &Entity<Buffer>,
 2998        buffer_position: language::Anchor,
 2999        cx: &App,
 3000    ) -> bool {
 3001        let snapshot = buffer.read(cx).snapshot();
 3002        let settings = snapshot.settings_at(buffer_position, cx);
 3003
 3004        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3005            return false;
 3006        };
 3007
 3008        scope.override_name().is_some_and(|scope_name| {
 3009            settings
 3010                .edit_predictions_disabled_in
 3011                .iter()
 3012                .any(|s| s == scope_name)
 3013        })
 3014    }
 3015
 3016    pub fn set_use_modal_editing(&mut self, to: bool) {
 3017        self.use_modal_editing = to;
 3018    }
 3019
 3020    pub fn use_modal_editing(&self) -> bool {
 3021        self.use_modal_editing
 3022    }
 3023
 3024    fn selections_did_change(
 3025        &mut self,
 3026        local: bool,
 3027        old_cursor_position: &Anchor,
 3028        effects: SelectionEffects,
 3029        window: &mut Window,
 3030        cx: &mut Context<Self>,
 3031    ) {
 3032        window.invalidate_character_coordinates();
 3033
 3034        // Copy selections to primary selection buffer
 3035        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3036        if local {
 3037            let selections = self.selections.all::<usize>(cx);
 3038            let buffer_handle = self.buffer.read(cx).read(cx);
 3039
 3040            let mut text = String::new();
 3041            for (index, selection) in selections.iter().enumerate() {
 3042                let text_for_selection = buffer_handle
 3043                    .text_for_range(selection.start..selection.end)
 3044                    .collect::<String>();
 3045
 3046                text.push_str(&text_for_selection);
 3047                if index != selections.len() - 1 {
 3048                    text.push('\n');
 3049                }
 3050            }
 3051
 3052            if !text.is_empty() {
 3053                cx.write_to_primary(ClipboardItem::new_string(text));
 3054            }
 3055        }
 3056
 3057        let selection_anchors = self.selections.disjoint_anchors();
 3058
 3059        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3060            self.buffer.update(cx, |buffer, cx| {
 3061                buffer.set_active_selections(
 3062                    &selection_anchors,
 3063                    self.selections.line_mode,
 3064                    self.cursor_shape,
 3065                    cx,
 3066                )
 3067            });
 3068        }
 3069        let display_map = self
 3070            .display_map
 3071            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3072        let buffer = &display_map.buffer_snapshot;
 3073        if self.selections.count() == 1 {
 3074            self.add_selections_state = None;
 3075        }
 3076        self.select_next_state = None;
 3077        self.select_prev_state = None;
 3078        self.select_syntax_node_history.try_clear();
 3079        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3080        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3081        self.take_rename(false, window, cx);
 3082
 3083        let newest_selection = self.selections.newest_anchor();
 3084        let new_cursor_position = newest_selection.head();
 3085        let selection_start = newest_selection.start;
 3086
 3087        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3088            self.push_to_nav_history(
 3089                *old_cursor_position,
 3090                Some(new_cursor_position.to_point(buffer)),
 3091                false,
 3092                effects.nav_history == Some(true),
 3093                cx,
 3094            );
 3095        }
 3096
 3097        if local {
 3098            if let Some(buffer_id) = new_cursor_position.buffer_id
 3099                && !self.registered_buffers.contains_key(&buffer_id)
 3100                && let Some(project) = self.project.as_ref()
 3101            {
 3102                project.update(cx, |project, cx| {
 3103                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3104                        return;
 3105                    };
 3106                    self.registered_buffers.insert(
 3107                        buffer_id,
 3108                        project.register_buffer_with_language_servers(&buffer, cx),
 3109                    );
 3110                })
 3111            }
 3112
 3113            let mut context_menu = self.context_menu.borrow_mut();
 3114            let completion_menu = match context_menu.as_ref() {
 3115                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3116                Some(CodeContextMenu::CodeActions(_)) => {
 3117                    *context_menu = None;
 3118                    None
 3119                }
 3120                None => None,
 3121            };
 3122            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3123            drop(context_menu);
 3124
 3125            if effects.completions
 3126                && let Some(completion_position) = completion_position
 3127            {
 3128                let start_offset = selection_start.to_offset(buffer);
 3129                let position_matches = start_offset == completion_position.to_offset(buffer);
 3130                let continue_showing = if position_matches {
 3131                    if self.snippet_stack.is_empty() {
 3132                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3133                    } else {
 3134                        // Snippet choices can be shown even when the cursor is in whitespace.
 3135                        // Dismissing the menu with actions like backspace is handled by
 3136                        // invalidation regions.
 3137                        true
 3138                    }
 3139                } else {
 3140                    false
 3141                };
 3142
 3143                if continue_showing {
 3144                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3145                } else {
 3146                    self.hide_context_menu(window, cx);
 3147                }
 3148            }
 3149
 3150            hide_hover(self, cx);
 3151
 3152            if old_cursor_position.to_display_point(&display_map).row()
 3153                != new_cursor_position.to_display_point(&display_map).row()
 3154            {
 3155                self.available_code_actions.take();
 3156            }
 3157            self.refresh_code_actions(window, cx);
 3158            self.refresh_document_highlights(cx);
 3159            self.refresh_selected_text_highlights(false, window, cx);
 3160            refresh_matching_bracket_highlights(self, window, cx);
 3161            self.update_visible_edit_prediction(window, cx);
 3162            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3163            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3164            self.inline_blame_popover.take();
 3165            if self.git_blame_inline_enabled {
 3166                self.start_inline_blame_timer(window, cx);
 3167            }
 3168        }
 3169
 3170        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3171        cx.emit(EditorEvent::SelectionsChanged { local });
 3172
 3173        let selections = &self.selections.disjoint;
 3174        if selections.len() == 1 {
 3175            cx.emit(SearchEvent::ActiveMatchChanged)
 3176        }
 3177        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3178            let inmemory_selections = selections
 3179                .iter()
 3180                .map(|s| {
 3181                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3182                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3183                })
 3184                .collect();
 3185            self.update_restoration_data(cx, |data| {
 3186                data.selections = inmemory_selections;
 3187            });
 3188
 3189            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3190                && let Some(workspace_id) =
 3191                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3192            {
 3193                let snapshot = self.buffer().read(cx).snapshot(cx);
 3194                let selections = selections.clone();
 3195                let background_executor = cx.background_executor().clone();
 3196                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3197                self.serialize_selections = cx.background_spawn(async move {
 3198                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3199                            let db_selections = selections
 3200                                .iter()
 3201                                .map(|selection| {
 3202                                    (
 3203                                        selection.start.to_offset(&snapshot),
 3204                                        selection.end.to_offset(&snapshot),
 3205                                    )
 3206                                })
 3207                                .collect();
 3208
 3209                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3210                                .await
 3211                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3212                                .log_err();
 3213                        });
 3214            }
 3215        }
 3216
 3217        cx.notify();
 3218    }
 3219
 3220    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3221        use text::ToOffset as _;
 3222        use text::ToPoint as _;
 3223
 3224        if self.mode.is_minimap()
 3225            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3226        {
 3227            return;
 3228        }
 3229
 3230        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3231            return;
 3232        };
 3233
 3234        let snapshot = singleton.read(cx).snapshot();
 3235        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3236            let display_snapshot = display_map.snapshot(cx);
 3237
 3238            display_snapshot
 3239                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3240                .map(|fold| {
 3241                    fold.range.start.text_anchor.to_point(&snapshot)
 3242                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3243                })
 3244                .collect()
 3245        });
 3246        self.update_restoration_data(cx, |data| {
 3247            data.folds = inmemory_folds;
 3248        });
 3249
 3250        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3251            return;
 3252        };
 3253        let background_executor = cx.background_executor().clone();
 3254        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3255        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3256            display_map
 3257                .snapshot(cx)
 3258                .folds_in_range(0..snapshot.len())
 3259                .map(|fold| {
 3260                    (
 3261                        fold.range.start.text_anchor.to_offset(&snapshot),
 3262                        fold.range.end.text_anchor.to_offset(&snapshot),
 3263                    )
 3264                })
 3265                .collect()
 3266        });
 3267        self.serialize_folds = cx.background_spawn(async move {
 3268            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3269            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3270                .await
 3271                .with_context(|| {
 3272                    format!(
 3273                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3274                    )
 3275                })
 3276                .log_err();
 3277        });
 3278    }
 3279
 3280    pub fn sync_selections(
 3281        &mut self,
 3282        other: Entity<Editor>,
 3283        cx: &mut Context<Self>,
 3284    ) -> gpui::Subscription {
 3285        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3286        self.selections.change_with(cx, |selections| {
 3287            selections.select_anchors(other_selections);
 3288        });
 3289
 3290        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3291            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3292                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3293                if other_selections.is_empty() {
 3294                    return;
 3295                }
 3296                this.selections.change_with(cx, |selections| {
 3297                    selections.select_anchors(other_selections);
 3298                });
 3299            }
 3300        });
 3301
 3302        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3303            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3304                let these_selections = this.selections.disjoint.to_vec();
 3305                if these_selections.is_empty() {
 3306                    return;
 3307                }
 3308                other.update(cx, |other_editor, cx| {
 3309                    other_editor.selections.change_with(cx, |selections| {
 3310                        selections.select_anchors(these_selections);
 3311                    })
 3312                });
 3313            }
 3314        });
 3315
 3316        Subscription::join(other_subscription, this_subscription)
 3317    }
 3318
 3319    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3320    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3321    /// effects of selection change occur at the end of the transaction.
 3322    pub fn change_selections<R>(
 3323        &mut self,
 3324        effects: SelectionEffects,
 3325        window: &mut Window,
 3326        cx: &mut Context<Self>,
 3327        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3328    ) -> R {
 3329        if let Some(state) = &mut self.deferred_selection_effects_state {
 3330            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3331            state.effects.completions = effects.completions;
 3332            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3333            let (changed, result) = self.selections.change_with(cx, change);
 3334            state.changed |= changed;
 3335            return result;
 3336        }
 3337        let mut state = DeferredSelectionEffectsState {
 3338            changed: false,
 3339            effects,
 3340            old_cursor_position: self.selections.newest_anchor().head(),
 3341            history_entry: SelectionHistoryEntry {
 3342                selections: self.selections.disjoint_anchors(),
 3343                select_next_state: self.select_next_state.clone(),
 3344                select_prev_state: self.select_prev_state.clone(),
 3345                add_selections_state: self.add_selections_state.clone(),
 3346            },
 3347        };
 3348        let (changed, result) = self.selections.change_with(cx, change);
 3349        state.changed = state.changed || changed;
 3350        if self.defer_selection_effects {
 3351            self.deferred_selection_effects_state = Some(state);
 3352        } else {
 3353            self.apply_selection_effects(state, window, cx);
 3354        }
 3355        result
 3356    }
 3357
 3358    /// Defers the effects of selection change, so that the effects of multiple calls to
 3359    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3360    /// to selection history and the state of popovers based on selection position aren't
 3361    /// erroneously updated.
 3362    pub fn with_selection_effects_deferred<R>(
 3363        &mut self,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3367    ) -> R {
 3368        let already_deferred = self.defer_selection_effects;
 3369        self.defer_selection_effects = true;
 3370        let result = update(self, window, cx);
 3371        if !already_deferred {
 3372            self.defer_selection_effects = false;
 3373            if let Some(state) = self.deferred_selection_effects_state.take() {
 3374                self.apply_selection_effects(state, window, cx);
 3375            }
 3376        }
 3377        result
 3378    }
 3379
 3380    fn apply_selection_effects(
 3381        &mut self,
 3382        state: DeferredSelectionEffectsState,
 3383        window: &mut Window,
 3384        cx: &mut Context<Self>,
 3385    ) {
 3386        if state.changed {
 3387            self.selection_history.push(state.history_entry);
 3388
 3389            if let Some(autoscroll) = state.effects.scroll {
 3390                self.request_autoscroll(autoscroll, cx);
 3391            }
 3392
 3393            let old_cursor_position = &state.old_cursor_position;
 3394
 3395            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3396
 3397            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3398                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3399            }
 3400        }
 3401    }
 3402
 3403    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3404    where
 3405        I: IntoIterator<Item = (Range<S>, T)>,
 3406        S: ToOffset,
 3407        T: Into<Arc<str>>,
 3408    {
 3409        if self.read_only(cx) {
 3410            return;
 3411        }
 3412
 3413        self.buffer
 3414            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3415    }
 3416
 3417    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3418    where
 3419        I: IntoIterator<Item = (Range<S>, T)>,
 3420        S: ToOffset,
 3421        T: Into<Arc<str>>,
 3422    {
 3423        if self.read_only(cx) {
 3424            return;
 3425        }
 3426
 3427        self.buffer.update(cx, |buffer, cx| {
 3428            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3429        });
 3430    }
 3431
 3432    pub fn edit_with_block_indent<I, S, T>(
 3433        &mut self,
 3434        edits: I,
 3435        original_indent_columns: Vec<Option<u32>>,
 3436        cx: &mut Context<Self>,
 3437    ) where
 3438        I: IntoIterator<Item = (Range<S>, T)>,
 3439        S: ToOffset,
 3440        T: Into<Arc<str>>,
 3441    {
 3442        if self.read_only(cx) {
 3443            return;
 3444        }
 3445
 3446        self.buffer.update(cx, |buffer, cx| {
 3447            buffer.edit(
 3448                edits,
 3449                Some(AutoindentMode::Block {
 3450                    original_indent_columns,
 3451                }),
 3452                cx,
 3453            )
 3454        });
 3455    }
 3456
 3457    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3458        self.hide_context_menu(window, cx);
 3459
 3460        match phase {
 3461            SelectPhase::Begin {
 3462                position,
 3463                add,
 3464                click_count,
 3465            } => self.begin_selection(position, add, click_count, window, cx),
 3466            SelectPhase::BeginColumnar {
 3467                position,
 3468                goal_column,
 3469                reset,
 3470                mode,
 3471            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3472            SelectPhase::Extend {
 3473                position,
 3474                click_count,
 3475            } => self.extend_selection(position, click_count, window, cx),
 3476            SelectPhase::Update {
 3477                position,
 3478                goal_column,
 3479                scroll_delta,
 3480            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3481            SelectPhase::End => self.end_selection(window, cx),
 3482        }
 3483    }
 3484
 3485    fn extend_selection(
 3486        &mut self,
 3487        position: DisplayPoint,
 3488        click_count: usize,
 3489        window: &mut Window,
 3490        cx: &mut Context<Self>,
 3491    ) {
 3492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3493        let tail = self.selections.newest::<usize>(cx).tail();
 3494        self.begin_selection(position, false, click_count, window, cx);
 3495
 3496        let position = position.to_offset(&display_map, Bias::Left);
 3497        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3498
 3499        let mut pending_selection = self
 3500            .selections
 3501            .pending_anchor()
 3502            .expect("extend_selection not called with pending selection");
 3503        if position >= tail {
 3504            pending_selection.start = tail_anchor;
 3505        } else {
 3506            pending_selection.end = tail_anchor;
 3507            pending_selection.reversed = true;
 3508        }
 3509
 3510        let mut pending_mode = self.selections.pending_mode().unwrap();
 3511        match &mut pending_mode {
 3512            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3513            _ => {}
 3514        }
 3515
 3516        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3517            SelectionEffects::scroll(Autoscroll::fit())
 3518        } else {
 3519            SelectionEffects::no_scroll()
 3520        };
 3521
 3522        self.change_selections(effects, window, cx, |s| {
 3523            s.set_pending(pending_selection, pending_mode)
 3524        });
 3525    }
 3526
 3527    fn begin_selection(
 3528        &mut self,
 3529        position: DisplayPoint,
 3530        add: bool,
 3531        click_count: usize,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if !self.focus_handle.is_focused(window) {
 3536            self.last_focused_descendant = None;
 3537            window.focus(&self.focus_handle);
 3538        }
 3539
 3540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3541        let buffer = &display_map.buffer_snapshot;
 3542        let position = display_map.clip_point(position, Bias::Left);
 3543
 3544        let start;
 3545        let end;
 3546        let mode;
 3547        let mut auto_scroll;
 3548        match click_count {
 3549            1 => {
 3550                start = buffer.anchor_before(position.to_point(&display_map));
 3551                end = start;
 3552                mode = SelectMode::Character;
 3553                auto_scroll = true;
 3554            }
 3555            2 => {
 3556                let position = display_map
 3557                    .clip_point(position, Bias::Left)
 3558                    .to_offset(&display_map, Bias::Left);
 3559                let (range, _) = buffer.surrounding_word(position, false);
 3560                start = buffer.anchor_before(range.start);
 3561                end = buffer.anchor_before(range.end);
 3562                mode = SelectMode::Word(start..end);
 3563                auto_scroll = true;
 3564            }
 3565            3 => {
 3566                let position = display_map
 3567                    .clip_point(position, Bias::Left)
 3568                    .to_point(&display_map);
 3569                let line_start = display_map.prev_line_boundary(position).0;
 3570                let next_line_start = buffer.clip_point(
 3571                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3572                    Bias::Left,
 3573                );
 3574                start = buffer.anchor_before(line_start);
 3575                end = buffer.anchor_before(next_line_start);
 3576                mode = SelectMode::Line(start..end);
 3577                auto_scroll = true;
 3578            }
 3579            _ => {
 3580                start = buffer.anchor_before(0);
 3581                end = buffer.anchor_before(buffer.len());
 3582                mode = SelectMode::All;
 3583                auto_scroll = false;
 3584            }
 3585        }
 3586        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3587
 3588        let point_to_delete: Option<usize> = {
 3589            let selected_points: Vec<Selection<Point>> =
 3590                self.selections.disjoint_in_range(start..end, cx);
 3591
 3592            if !add || click_count > 1 {
 3593                None
 3594            } else if !selected_points.is_empty() {
 3595                Some(selected_points[0].id)
 3596            } else {
 3597                let clicked_point_already_selected =
 3598                    self.selections.disjoint.iter().find(|selection| {
 3599                        selection.start.to_point(buffer) == start.to_point(buffer)
 3600                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3601                    });
 3602
 3603                clicked_point_already_selected.map(|selection| selection.id)
 3604            }
 3605        };
 3606
 3607        let selections_count = self.selections.count();
 3608        let effects = if auto_scroll {
 3609            SelectionEffects::default()
 3610        } else {
 3611            SelectionEffects::no_scroll()
 3612        };
 3613
 3614        self.change_selections(effects, window, cx, |s| {
 3615            if let Some(point_to_delete) = point_to_delete {
 3616                s.delete(point_to_delete);
 3617
 3618                if selections_count == 1 {
 3619                    s.set_pending_anchor_range(start..end, mode);
 3620                }
 3621            } else {
 3622                if !add {
 3623                    s.clear_disjoint();
 3624                }
 3625
 3626                s.set_pending_anchor_range(start..end, mode);
 3627            }
 3628        });
 3629    }
 3630
 3631    fn begin_columnar_selection(
 3632        &mut self,
 3633        position: DisplayPoint,
 3634        goal_column: u32,
 3635        reset: bool,
 3636        mode: ColumnarMode,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639    ) {
 3640        if !self.focus_handle.is_focused(window) {
 3641            self.last_focused_descendant = None;
 3642            window.focus(&self.focus_handle);
 3643        }
 3644
 3645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3646
 3647        if reset {
 3648            let pointer_position = display_map
 3649                .buffer_snapshot
 3650                .anchor_before(position.to_point(&display_map));
 3651
 3652            self.change_selections(
 3653                SelectionEffects::scroll(Autoscroll::newest()),
 3654                window,
 3655                cx,
 3656                |s| {
 3657                    s.clear_disjoint();
 3658                    s.set_pending_anchor_range(
 3659                        pointer_position..pointer_position,
 3660                        SelectMode::Character,
 3661                    );
 3662                },
 3663            );
 3664        };
 3665
 3666        let tail = self.selections.newest::<Point>(cx).tail();
 3667        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3668        self.columnar_selection_state = match mode {
 3669            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3670                selection_tail: selection_anchor,
 3671                display_point: if reset {
 3672                    if position.column() != goal_column {
 3673                        Some(DisplayPoint::new(position.row(), goal_column))
 3674                    } else {
 3675                        None
 3676                    }
 3677                } else {
 3678                    None
 3679                },
 3680            }),
 3681            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3682                selection_tail: selection_anchor,
 3683            }),
 3684        };
 3685
 3686        if !reset {
 3687            self.select_columns(position, goal_column, &display_map, window, cx);
 3688        }
 3689    }
 3690
 3691    fn update_selection(
 3692        &mut self,
 3693        position: DisplayPoint,
 3694        goal_column: u32,
 3695        scroll_delta: gpui::Point<f32>,
 3696        window: &mut Window,
 3697        cx: &mut Context<Self>,
 3698    ) {
 3699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3700
 3701        if self.columnar_selection_state.is_some() {
 3702            self.select_columns(position, goal_column, &display_map, window, cx);
 3703        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3704            let buffer = &display_map.buffer_snapshot;
 3705            let head;
 3706            let tail;
 3707            let mode = self.selections.pending_mode().unwrap();
 3708            match &mode {
 3709                SelectMode::Character => {
 3710                    head = position.to_point(&display_map);
 3711                    tail = pending.tail().to_point(buffer);
 3712                }
 3713                SelectMode::Word(original_range) => {
 3714                    let offset = display_map
 3715                        .clip_point(position, Bias::Left)
 3716                        .to_offset(&display_map, Bias::Left);
 3717                    let original_range = original_range.to_offset(buffer);
 3718
 3719                    let head_offset = if buffer.is_inside_word(offset, false)
 3720                        || original_range.contains(&offset)
 3721                    {
 3722                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3723                        if word_range.start < original_range.start {
 3724                            word_range.start
 3725                        } else {
 3726                            word_range.end
 3727                        }
 3728                    } else {
 3729                        offset
 3730                    };
 3731
 3732                    head = head_offset.to_point(buffer);
 3733                    if head_offset <= original_range.start {
 3734                        tail = original_range.end.to_point(buffer);
 3735                    } else {
 3736                        tail = original_range.start.to_point(buffer);
 3737                    }
 3738                }
 3739                SelectMode::Line(original_range) => {
 3740                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3741
 3742                    let position = display_map
 3743                        .clip_point(position, Bias::Left)
 3744                        .to_point(&display_map);
 3745                    let line_start = display_map.prev_line_boundary(position).0;
 3746                    let next_line_start = buffer.clip_point(
 3747                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3748                        Bias::Left,
 3749                    );
 3750
 3751                    if line_start < original_range.start {
 3752                        head = line_start
 3753                    } else {
 3754                        head = next_line_start
 3755                    }
 3756
 3757                    if head <= original_range.start {
 3758                        tail = original_range.end;
 3759                    } else {
 3760                        tail = original_range.start;
 3761                    }
 3762                }
 3763                SelectMode::All => {
 3764                    return;
 3765                }
 3766            };
 3767
 3768            if head < tail {
 3769                pending.start = buffer.anchor_before(head);
 3770                pending.end = buffer.anchor_before(tail);
 3771                pending.reversed = true;
 3772            } else {
 3773                pending.start = buffer.anchor_before(tail);
 3774                pending.end = buffer.anchor_before(head);
 3775                pending.reversed = false;
 3776            }
 3777
 3778            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3779                s.set_pending(pending, mode);
 3780            });
 3781        } else {
 3782            log::error!("update_selection dispatched with no pending selection");
 3783            return;
 3784        }
 3785
 3786        self.apply_scroll_delta(scroll_delta, window, cx);
 3787        cx.notify();
 3788    }
 3789
 3790    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3791        self.columnar_selection_state.take();
 3792        if self.selections.pending_anchor().is_some() {
 3793            let selections = self.selections.all::<usize>(cx);
 3794            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3795                s.select(selections);
 3796                s.clear_pending();
 3797            });
 3798        }
 3799    }
 3800
 3801    fn select_columns(
 3802        &mut self,
 3803        head: DisplayPoint,
 3804        goal_column: u32,
 3805        display_map: &DisplaySnapshot,
 3806        window: &mut Window,
 3807        cx: &mut Context<Self>,
 3808    ) {
 3809        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3810            return;
 3811        };
 3812
 3813        let tail = match columnar_state {
 3814            ColumnarSelectionState::FromMouse {
 3815                selection_tail,
 3816                display_point,
 3817            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3818            ColumnarSelectionState::FromSelection { selection_tail } => {
 3819                selection_tail.to_display_point(display_map)
 3820            }
 3821        };
 3822
 3823        let start_row = cmp::min(tail.row(), head.row());
 3824        let end_row = cmp::max(tail.row(), head.row());
 3825        let start_column = cmp::min(tail.column(), goal_column);
 3826        let end_column = cmp::max(tail.column(), goal_column);
 3827        let reversed = start_column < tail.column();
 3828
 3829        let selection_ranges = (start_row.0..=end_row.0)
 3830            .map(DisplayRow)
 3831            .filter_map(|row| {
 3832                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3833                    || start_column <= display_map.line_len(row))
 3834                    && !display_map.is_block_line(row)
 3835                {
 3836                    let start = display_map
 3837                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3838                        .to_point(display_map);
 3839                    let end = display_map
 3840                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3841                        .to_point(display_map);
 3842                    if reversed {
 3843                        Some(end..start)
 3844                    } else {
 3845                        Some(start..end)
 3846                    }
 3847                } else {
 3848                    None
 3849                }
 3850            })
 3851            .collect::<Vec<_>>();
 3852
 3853        let ranges = match columnar_state {
 3854            ColumnarSelectionState::FromMouse { .. } => {
 3855                let mut non_empty_ranges = selection_ranges
 3856                    .iter()
 3857                    .filter(|selection_range| selection_range.start != selection_range.end)
 3858                    .peekable();
 3859                if non_empty_ranges.peek().is_some() {
 3860                    non_empty_ranges.cloned().collect()
 3861                } else {
 3862                    selection_ranges
 3863                }
 3864            }
 3865            _ => selection_ranges,
 3866        };
 3867
 3868        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3869            s.select_ranges(ranges);
 3870        });
 3871        cx.notify();
 3872    }
 3873
 3874    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3875        self.selections
 3876            .all_adjusted(cx)
 3877            .iter()
 3878            .any(|selection| !selection.is_empty())
 3879    }
 3880
 3881    pub fn has_pending_nonempty_selection(&self) -> bool {
 3882        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3883            Some(Selection { start, end, .. }) => start != end,
 3884            None => false,
 3885        };
 3886
 3887        pending_nonempty_selection
 3888            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3889    }
 3890
 3891    pub fn has_pending_selection(&self) -> bool {
 3892        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3893    }
 3894
 3895    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3896        self.selection_mark_mode = false;
 3897        self.selection_drag_state = SelectionDragState::None;
 3898
 3899        if self.clear_expanded_diff_hunks(cx) {
 3900            cx.notify();
 3901            return;
 3902        }
 3903        if self.dismiss_menus_and_popups(true, window, cx) {
 3904            return;
 3905        }
 3906
 3907        if self.mode.is_full()
 3908            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3909        {
 3910            return;
 3911        }
 3912
 3913        cx.propagate();
 3914    }
 3915
 3916    pub fn dismiss_menus_and_popups(
 3917        &mut self,
 3918        is_user_requested: bool,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) -> bool {
 3922        if self.take_rename(false, window, cx).is_some() {
 3923            return true;
 3924        }
 3925
 3926        if hide_hover(self, cx) {
 3927            return true;
 3928        }
 3929
 3930        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3931            return true;
 3932        }
 3933
 3934        if self.hide_context_menu(window, cx).is_some() {
 3935            return true;
 3936        }
 3937
 3938        if self.mouse_context_menu.take().is_some() {
 3939            return true;
 3940        }
 3941
 3942        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3943            return true;
 3944        }
 3945
 3946        if self.snippet_stack.pop().is_some() {
 3947            return true;
 3948        }
 3949
 3950        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3951            self.dismiss_diagnostics(cx);
 3952            return true;
 3953        }
 3954
 3955        false
 3956    }
 3957
 3958    fn linked_editing_ranges_for(
 3959        &self,
 3960        selection: Range<text::Anchor>,
 3961        cx: &App,
 3962    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3963        if self.linked_edit_ranges.is_empty() {
 3964            return None;
 3965        }
 3966        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3967            selection.end.buffer_id.and_then(|end_buffer_id| {
 3968                if selection.start.buffer_id != Some(end_buffer_id) {
 3969                    return None;
 3970                }
 3971                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3972                let snapshot = buffer.read(cx).snapshot();
 3973                self.linked_edit_ranges
 3974                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3975                    .map(|ranges| (ranges, snapshot, buffer))
 3976            })?;
 3977        use text::ToOffset as TO;
 3978        // find offset from the start of current range to current cursor position
 3979        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3980
 3981        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3982        let start_difference = start_offset - start_byte_offset;
 3983        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3984        let end_difference = end_offset - start_byte_offset;
 3985        // Current range has associated linked ranges.
 3986        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3987        for range in linked_ranges.iter() {
 3988            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3989            let end_offset = start_offset + end_difference;
 3990            let start_offset = start_offset + start_difference;
 3991            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3992                continue;
 3993            }
 3994            if self.selections.disjoint_anchor_ranges().any(|s| {
 3995                if s.start.buffer_id != selection.start.buffer_id
 3996                    || s.end.buffer_id != selection.end.buffer_id
 3997                {
 3998                    return false;
 3999                }
 4000                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4001                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4002            }) {
 4003                continue;
 4004            }
 4005            let start = buffer_snapshot.anchor_after(start_offset);
 4006            let end = buffer_snapshot.anchor_after(end_offset);
 4007            linked_edits
 4008                .entry(buffer.clone())
 4009                .or_default()
 4010                .push(start..end);
 4011        }
 4012        Some(linked_edits)
 4013    }
 4014
 4015    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4016        let text: Arc<str> = text.into();
 4017
 4018        if self.read_only(cx) {
 4019            return;
 4020        }
 4021
 4022        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4023
 4024        let selections = self.selections.all_adjusted(cx);
 4025        let mut bracket_inserted = false;
 4026        let mut edits = Vec::new();
 4027        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4028        let mut new_selections = Vec::with_capacity(selections.len());
 4029        let mut new_autoclose_regions = Vec::new();
 4030        let snapshot = self.buffer.read(cx).read(cx);
 4031        let mut clear_linked_edit_ranges = false;
 4032
 4033        for (selection, autoclose_region) in
 4034            self.selections_with_autoclose_regions(selections, &snapshot)
 4035        {
 4036            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4037                // Determine if the inserted text matches the opening or closing
 4038                // bracket of any of this language's bracket pairs.
 4039                let mut bracket_pair = None;
 4040                let mut is_bracket_pair_start = false;
 4041                let mut is_bracket_pair_end = false;
 4042                if !text.is_empty() {
 4043                    let mut bracket_pair_matching_end = None;
 4044                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4045                    //  and they are removing the character that triggered IME popup.
 4046                    for (pair, enabled) in scope.brackets() {
 4047                        if !pair.close && !pair.surround {
 4048                            continue;
 4049                        }
 4050
 4051                        if enabled && pair.start.ends_with(text.as_ref()) {
 4052                            let prefix_len = pair.start.len() - text.len();
 4053                            let preceding_text_matches_prefix = prefix_len == 0
 4054                                || (selection.start.column >= (prefix_len as u32)
 4055                                    && snapshot.contains_str_at(
 4056                                        Point::new(
 4057                                            selection.start.row,
 4058                                            selection.start.column - (prefix_len as u32),
 4059                                        ),
 4060                                        &pair.start[..prefix_len],
 4061                                    ));
 4062                            if preceding_text_matches_prefix {
 4063                                bracket_pair = Some(pair.clone());
 4064                                is_bracket_pair_start = true;
 4065                                break;
 4066                            }
 4067                        }
 4068                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4069                        {
 4070                            // take first bracket pair matching end, but don't break in case a later bracket
 4071                            // pair matches start
 4072                            bracket_pair_matching_end = Some(pair.clone());
 4073                        }
 4074                    }
 4075                    if let Some(end) = bracket_pair_matching_end
 4076                        && bracket_pair.is_none()
 4077                    {
 4078                        bracket_pair = Some(end);
 4079                        is_bracket_pair_end = true;
 4080                    }
 4081                }
 4082
 4083                if let Some(bracket_pair) = bracket_pair {
 4084                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4085                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4086                    let auto_surround =
 4087                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4088                    if selection.is_empty() {
 4089                        if is_bracket_pair_start {
 4090                            // If the inserted text is a suffix of an opening bracket and the
 4091                            // selection is preceded by the rest of the opening bracket, then
 4092                            // insert the closing bracket.
 4093                            let following_text_allows_autoclose = snapshot
 4094                                .chars_at(selection.start)
 4095                                .next()
 4096                                .is_none_or(|c| scope.should_autoclose_before(c));
 4097
 4098                            let preceding_text_allows_autoclose = selection.start.column == 0
 4099                                || snapshot
 4100                                    .reversed_chars_at(selection.start)
 4101                                    .next()
 4102                                    .is_none_or(|c| {
 4103                                        bracket_pair.start != bracket_pair.end
 4104                                            || !snapshot
 4105                                                .char_classifier_at(selection.start)
 4106                                                .is_word(c)
 4107                                    });
 4108
 4109                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4110                                && bracket_pair.start.len() == 1
 4111                            {
 4112                                let target = bracket_pair.start.chars().next().unwrap();
 4113                                let current_line_count = snapshot
 4114                                    .reversed_chars_at(selection.start)
 4115                                    .take_while(|&c| c != '\n')
 4116                                    .filter(|&c| c == target)
 4117                                    .count();
 4118                                current_line_count % 2 == 1
 4119                            } else {
 4120                                false
 4121                            };
 4122
 4123                            if autoclose
 4124                                && bracket_pair.close
 4125                                && following_text_allows_autoclose
 4126                                && preceding_text_allows_autoclose
 4127                                && !is_closing_quote
 4128                            {
 4129                                let anchor = snapshot.anchor_before(selection.end);
 4130                                new_selections.push((selection.map(|_| anchor), text.len()));
 4131                                new_autoclose_regions.push((
 4132                                    anchor,
 4133                                    text.len(),
 4134                                    selection.id,
 4135                                    bracket_pair.clone(),
 4136                                ));
 4137                                edits.push((
 4138                                    selection.range(),
 4139                                    format!("{}{}", text, bracket_pair.end).into(),
 4140                                ));
 4141                                bracket_inserted = true;
 4142                                continue;
 4143                            }
 4144                        }
 4145
 4146                        if let Some(region) = autoclose_region {
 4147                            // If the selection is followed by an auto-inserted closing bracket,
 4148                            // then don't insert that closing bracket again; just move the selection
 4149                            // past the closing bracket.
 4150                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4151                                && text.as_ref() == region.pair.end.as_str()
 4152                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4153                            if should_skip {
 4154                                let anchor = snapshot.anchor_after(selection.end);
 4155                                new_selections
 4156                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4157                                continue;
 4158                            }
 4159                        }
 4160
 4161                        let always_treat_brackets_as_autoclosed = snapshot
 4162                            .language_settings_at(selection.start, cx)
 4163                            .always_treat_brackets_as_autoclosed;
 4164                        if always_treat_brackets_as_autoclosed
 4165                            && is_bracket_pair_end
 4166                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4167                        {
 4168                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4169                            // and the inserted text is a closing bracket and the selection is followed
 4170                            // by the closing bracket then move the selection past the closing bracket.
 4171                            let anchor = snapshot.anchor_after(selection.end);
 4172                            new_selections.push((selection.map(|_| anchor), text.len()));
 4173                            continue;
 4174                        }
 4175                    }
 4176                    // If an opening bracket is 1 character long and is typed while
 4177                    // text is selected, then surround that text with the bracket pair.
 4178                    else if auto_surround
 4179                        && bracket_pair.surround
 4180                        && is_bracket_pair_start
 4181                        && bracket_pair.start.chars().count() == 1
 4182                    {
 4183                        edits.push((selection.start..selection.start, text.clone()));
 4184                        edits.push((
 4185                            selection.end..selection.end,
 4186                            bracket_pair.end.as_str().into(),
 4187                        ));
 4188                        bracket_inserted = true;
 4189                        new_selections.push((
 4190                            Selection {
 4191                                id: selection.id,
 4192                                start: snapshot.anchor_after(selection.start),
 4193                                end: snapshot.anchor_before(selection.end),
 4194                                reversed: selection.reversed,
 4195                                goal: selection.goal,
 4196                            },
 4197                            0,
 4198                        ));
 4199                        continue;
 4200                    }
 4201                }
 4202            }
 4203
 4204            if self.auto_replace_emoji_shortcode
 4205                && selection.is_empty()
 4206                && text.as_ref().ends_with(':')
 4207                && let Some(possible_emoji_short_code) =
 4208                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4209                && !possible_emoji_short_code.is_empty()
 4210                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4211            {
 4212                let emoji_shortcode_start = Point::new(
 4213                    selection.start.row,
 4214                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4215                );
 4216
 4217                // Remove shortcode from buffer
 4218                edits.push((
 4219                    emoji_shortcode_start..selection.start,
 4220                    "".to_string().into(),
 4221                ));
 4222                new_selections.push((
 4223                    Selection {
 4224                        id: selection.id,
 4225                        start: snapshot.anchor_after(emoji_shortcode_start),
 4226                        end: snapshot.anchor_before(selection.start),
 4227                        reversed: selection.reversed,
 4228                        goal: selection.goal,
 4229                    },
 4230                    0,
 4231                ));
 4232
 4233                // Insert emoji
 4234                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4235                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4236                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4237
 4238                continue;
 4239            }
 4240
 4241            // If not handling any auto-close operation, then just replace the selected
 4242            // text with the given input and move the selection to the end of the
 4243            // newly inserted text.
 4244            let anchor = snapshot.anchor_after(selection.end);
 4245            if !self.linked_edit_ranges.is_empty() {
 4246                let start_anchor = snapshot.anchor_before(selection.start);
 4247
 4248                let is_word_char = text.chars().next().is_none_or(|char| {
 4249                    let classifier = snapshot
 4250                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4251                        .ignore_punctuation(true);
 4252                    classifier.is_word(char)
 4253                });
 4254
 4255                if is_word_char {
 4256                    if let Some(ranges) = self
 4257                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4258                    {
 4259                        for (buffer, edits) in ranges {
 4260                            linked_edits
 4261                                .entry(buffer.clone())
 4262                                .or_default()
 4263                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4264                        }
 4265                    }
 4266                } else {
 4267                    clear_linked_edit_ranges = true;
 4268                }
 4269            }
 4270
 4271            new_selections.push((selection.map(|_| anchor), 0));
 4272            edits.push((selection.start..selection.end, text.clone()));
 4273        }
 4274
 4275        drop(snapshot);
 4276
 4277        self.transact(window, cx, |this, window, cx| {
 4278            if clear_linked_edit_ranges {
 4279                this.linked_edit_ranges.clear();
 4280            }
 4281            let initial_buffer_versions =
 4282                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4283
 4284            this.buffer.update(cx, |buffer, cx| {
 4285                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4286            });
 4287            for (buffer, edits) in linked_edits {
 4288                buffer.update(cx, |buffer, cx| {
 4289                    let snapshot = buffer.snapshot();
 4290                    let edits = edits
 4291                        .into_iter()
 4292                        .map(|(range, text)| {
 4293                            use text::ToPoint as TP;
 4294                            let end_point = TP::to_point(&range.end, &snapshot);
 4295                            let start_point = TP::to_point(&range.start, &snapshot);
 4296                            (start_point..end_point, text)
 4297                        })
 4298                        .sorted_by_key(|(range, _)| range.start);
 4299                    buffer.edit(edits, None, cx);
 4300                })
 4301            }
 4302            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4303            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4304            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4305            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4306                .zip(new_selection_deltas)
 4307                .map(|(selection, delta)| Selection {
 4308                    id: selection.id,
 4309                    start: selection.start + delta,
 4310                    end: selection.end + delta,
 4311                    reversed: selection.reversed,
 4312                    goal: SelectionGoal::None,
 4313                })
 4314                .collect::<Vec<_>>();
 4315
 4316            let mut i = 0;
 4317            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4318                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4319                let start = map.buffer_snapshot.anchor_before(position);
 4320                let end = map.buffer_snapshot.anchor_after(position);
 4321                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4322                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4323                        Ordering::Less => i += 1,
 4324                        Ordering::Greater => break,
 4325                        Ordering::Equal => {
 4326                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4327                                Ordering::Less => i += 1,
 4328                                Ordering::Equal => break,
 4329                                Ordering::Greater => break,
 4330                            }
 4331                        }
 4332                    }
 4333                }
 4334                this.autoclose_regions.insert(
 4335                    i,
 4336                    AutocloseRegion {
 4337                        selection_id,
 4338                        range: start..end,
 4339                        pair,
 4340                    },
 4341                );
 4342            }
 4343
 4344            let had_active_edit_prediction = this.has_active_edit_prediction();
 4345            this.change_selections(
 4346                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4347                window,
 4348                cx,
 4349                |s| s.select(new_selections),
 4350            );
 4351
 4352            if !bracket_inserted
 4353                && let Some(on_type_format_task) =
 4354                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4355            {
 4356                on_type_format_task.detach_and_log_err(cx);
 4357            }
 4358
 4359            let editor_settings = EditorSettings::get_global(cx);
 4360            if bracket_inserted
 4361                && (editor_settings.auto_signature_help
 4362                    || editor_settings.show_signature_help_after_edits)
 4363            {
 4364                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4365            }
 4366
 4367            let trigger_in_words =
 4368                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4369            if this.hard_wrap.is_some() {
 4370                let latest: Range<Point> = this.selections.newest(cx).range();
 4371                if latest.is_empty()
 4372                    && this
 4373                        .buffer()
 4374                        .read(cx)
 4375                        .snapshot(cx)
 4376                        .line_len(MultiBufferRow(latest.start.row))
 4377                        == latest.start.column
 4378                {
 4379                    this.rewrap_impl(
 4380                        RewrapOptions {
 4381                            override_language_settings: true,
 4382                            preserve_existing_whitespace: true,
 4383                        },
 4384                        cx,
 4385                    )
 4386                }
 4387            }
 4388            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4389            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4390            this.refresh_edit_prediction(true, false, window, cx);
 4391            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4392        });
 4393    }
 4394
 4395    fn find_possible_emoji_shortcode_at_position(
 4396        snapshot: &MultiBufferSnapshot,
 4397        position: Point,
 4398    ) -> Option<String> {
 4399        let mut chars = Vec::new();
 4400        let mut found_colon = false;
 4401        for char in snapshot.reversed_chars_at(position).take(100) {
 4402            // Found a possible emoji shortcode in the middle of the buffer
 4403            if found_colon {
 4404                if char.is_whitespace() {
 4405                    chars.reverse();
 4406                    return Some(chars.iter().collect());
 4407                }
 4408                // If the previous character is not a whitespace, we are in the middle of a word
 4409                // and we only want to complete the shortcode if the word is made up of other emojis
 4410                let mut containing_word = String::new();
 4411                for ch in snapshot
 4412                    .reversed_chars_at(position)
 4413                    .skip(chars.len() + 1)
 4414                    .take(100)
 4415                {
 4416                    if ch.is_whitespace() {
 4417                        break;
 4418                    }
 4419                    containing_word.push(ch);
 4420                }
 4421                let containing_word = containing_word.chars().rev().collect::<String>();
 4422                if util::word_consists_of_emojis(containing_word.as_str()) {
 4423                    chars.reverse();
 4424                    return Some(chars.iter().collect());
 4425                }
 4426            }
 4427
 4428            if char.is_whitespace() || !char.is_ascii() {
 4429                return None;
 4430            }
 4431            if char == ':' {
 4432                found_colon = true;
 4433            } else {
 4434                chars.push(char);
 4435            }
 4436        }
 4437        // Found a possible emoji shortcode at the beginning of the buffer
 4438        chars.reverse();
 4439        Some(chars.iter().collect())
 4440    }
 4441
 4442    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4443        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4444        self.transact(window, cx, |this, window, cx| {
 4445            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4446                let selections = this.selections.all::<usize>(cx);
 4447                let multi_buffer = this.buffer.read(cx);
 4448                let buffer = multi_buffer.snapshot(cx);
 4449                selections
 4450                    .iter()
 4451                    .map(|selection| {
 4452                        let start_point = selection.start.to_point(&buffer);
 4453                        let mut existing_indent =
 4454                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4455                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4456                        let start = selection.start;
 4457                        let end = selection.end;
 4458                        let selection_is_empty = start == end;
 4459                        let language_scope = buffer.language_scope_at(start);
 4460                        let (
 4461                            comment_delimiter,
 4462                            doc_delimiter,
 4463                            insert_extra_newline,
 4464                            indent_on_newline,
 4465                            indent_on_extra_newline,
 4466                        ) = if let Some(language) = &language_scope {
 4467                            let mut insert_extra_newline =
 4468                                insert_extra_newline_brackets(&buffer, start..end, language)
 4469                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4470
 4471                            // Comment extension on newline is allowed only for cursor selections
 4472                            let comment_delimiter = maybe!({
 4473                                if !selection_is_empty {
 4474                                    return None;
 4475                                }
 4476
 4477                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4478                                    return None;
 4479                                }
 4480
 4481                                let delimiters = language.line_comment_prefixes();
 4482                                let max_len_of_delimiter =
 4483                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4484                                let (snapshot, range) =
 4485                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4486
 4487                                let num_of_whitespaces = snapshot
 4488                                    .chars_for_range(range.clone())
 4489                                    .take_while(|c| c.is_whitespace())
 4490                                    .count();
 4491                                let comment_candidate = snapshot
 4492                                    .chars_for_range(range.clone())
 4493                                    .skip(num_of_whitespaces)
 4494                                    .take(max_len_of_delimiter)
 4495                                    .collect::<String>();
 4496                                let (delimiter, trimmed_len) = delimiters
 4497                                    .iter()
 4498                                    .filter_map(|delimiter| {
 4499                                        let prefix = delimiter.trim_end();
 4500                                        if comment_candidate.starts_with(prefix) {
 4501                                            Some((delimiter, prefix.len()))
 4502                                        } else {
 4503                                            None
 4504                                        }
 4505                                    })
 4506                                    .max_by_key(|(_, len)| *len)?;
 4507
 4508                                if let Some(BlockCommentConfig {
 4509                                    start: block_start, ..
 4510                                }) = language.block_comment()
 4511                                {
 4512                                    let block_start_trimmed = block_start.trim_end();
 4513                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4514                                        let line_content = snapshot
 4515                                            .chars_for_range(range)
 4516                                            .skip(num_of_whitespaces)
 4517                                            .take(block_start_trimmed.len())
 4518                                            .collect::<String>();
 4519
 4520                                        if line_content.starts_with(block_start_trimmed) {
 4521                                            return None;
 4522                                        }
 4523                                    }
 4524                                }
 4525
 4526                                let cursor_is_placed_after_comment_marker =
 4527                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4528                                if cursor_is_placed_after_comment_marker {
 4529                                    Some(delimiter.clone())
 4530                                } else {
 4531                                    None
 4532                                }
 4533                            });
 4534
 4535                            let mut indent_on_newline = IndentSize::spaces(0);
 4536                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4537
 4538                            let doc_delimiter = maybe!({
 4539                                if !selection_is_empty {
 4540                                    return None;
 4541                                }
 4542
 4543                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4544                                    return None;
 4545                                }
 4546
 4547                                let BlockCommentConfig {
 4548                                    start: start_tag,
 4549                                    end: end_tag,
 4550                                    prefix: delimiter,
 4551                                    tab_size: len,
 4552                                } = language.documentation_comment()?;
 4553                                let is_within_block_comment = buffer
 4554                                    .language_scope_at(start_point)
 4555                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4556                                if !is_within_block_comment {
 4557                                    return None;
 4558                                }
 4559
 4560                                let (snapshot, range) =
 4561                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4562
 4563                                let num_of_whitespaces = snapshot
 4564                                    .chars_for_range(range.clone())
 4565                                    .take_while(|c| c.is_whitespace())
 4566                                    .count();
 4567
 4568                                // 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.
 4569                                let column = start_point.column;
 4570                                let cursor_is_after_start_tag = {
 4571                                    let start_tag_len = start_tag.len();
 4572                                    let start_tag_line = snapshot
 4573                                        .chars_for_range(range.clone())
 4574                                        .skip(num_of_whitespaces)
 4575                                        .take(start_tag_len)
 4576                                        .collect::<String>();
 4577                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4578                                        num_of_whitespaces + start_tag_len <= column as usize
 4579                                    } else {
 4580                                        false
 4581                                    }
 4582                                };
 4583
 4584                                let cursor_is_after_delimiter = {
 4585                                    let delimiter_trim = delimiter.trim_end();
 4586                                    let delimiter_line = snapshot
 4587                                        .chars_for_range(range.clone())
 4588                                        .skip(num_of_whitespaces)
 4589                                        .take(delimiter_trim.len())
 4590                                        .collect::<String>();
 4591                                    if delimiter_line.starts_with(delimiter_trim) {
 4592                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4593                                    } else {
 4594                                        false
 4595                                    }
 4596                                };
 4597
 4598                                let cursor_is_before_end_tag_if_exists = {
 4599                                    let mut char_position = 0u32;
 4600                                    let mut end_tag_offset = None;
 4601
 4602                                    'outer: for chunk in snapshot.text_for_range(range) {
 4603                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4604                                            let chars_before_match =
 4605                                                chunk[..byte_pos].chars().count() as u32;
 4606                                            end_tag_offset =
 4607                                                Some(char_position + chars_before_match);
 4608                                            break 'outer;
 4609                                        }
 4610                                        char_position += chunk.chars().count() as u32;
 4611                                    }
 4612
 4613                                    if let Some(end_tag_offset) = end_tag_offset {
 4614                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4615                                        if cursor_is_after_start_tag {
 4616                                            if cursor_is_before_end_tag {
 4617                                                insert_extra_newline = true;
 4618                                            }
 4619                                            let cursor_is_at_start_of_end_tag =
 4620                                                column == end_tag_offset;
 4621                                            if cursor_is_at_start_of_end_tag {
 4622                                                indent_on_extra_newline.len = *len;
 4623                                            }
 4624                                        }
 4625                                        cursor_is_before_end_tag
 4626                                    } else {
 4627                                        true
 4628                                    }
 4629                                };
 4630
 4631                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4632                                    && cursor_is_before_end_tag_if_exists
 4633                                {
 4634                                    if cursor_is_after_start_tag {
 4635                                        indent_on_newline.len = *len;
 4636                                    }
 4637                                    Some(delimiter.clone())
 4638                                } else {
 4639                                    None
 4640                                }
 4641                            });
 4642
 4643                            (
 4644                                comment_delimiter,
 4645                                doc_delimiter,
 4646                                insert_extra_newline,
 4647                                indent_on_newline,
 4648                                indent_on_extra_newline,
 4649                            )
 4650                        } else {
 4651                            (
 4652                                None,
 4653                                None,
 4654                                false,
 4655                                IndentSize::default(),
 4656                                IndentSize::default(),
 4657                            )
 4658                        };
 4659
 4660                        let prevent_auto_indent = doc_delimiter.is_some();
 4661                        let delimiter = comment_delimiter.or(doc_delimiter);
 4662
 4663                        let capacity_for_delimiter =
 4664                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4665                        let mut new_text = String::with_capacity(
 4666                            1 + capacity_for_delimiter
 4667                                + existing_indent.len as usize
 4668                                + indent_on_newline.len as usize
 4669                                + indent_on_extra_newline.len as usize,
 4670                        );
 4671                        new_text.push('\n');
 4672                        new_text.extend(existing_indent.chars());
 4673                        new_text.extend(indent_on_newline.chars());
 4674
 4675                        if let Some(delimiter) = &delimiter {
 4676                            new_text.push_str(delimiter);
 4677                        }
 4678
 4679                        if insert_extra_newline {
 4680                            new_text.push('\n');
 4681                            new_text.extend(existing_indent.chars());
 4682                            new_text.extend(indent_on_extra_newline.chars());
 4683                        }
 4684
 4685                        let anchor = buffer.anchor_after(end);
 4686                        let new_selection = selection.map(|_| anchor);
 4687                        (
 4688                            ((start..end, new_text), prevent_auto_indent),
 4689                            (insert_extra_newline, new_selection),
 4690                        )
 4691                    })
 4692                    .unzip()
 4693            };
 4694
 4695            let mut auto_indent_edits = Vec::new();
 4696            let mut edits = Vec::new();
 4697            for (edit, prevent_auto_indent) in edits_with_flags {
 4698                if prevent_auto_indent {
 4699                    edits.push(edit);
 4700                } else {
 4701                    auto_indent_edits.push(edit);
 4702                }
 4703            }
 4704            if !edits.is_empty() {
 4705                this.edit(edits, cx);
 4706            }
 4707            if !auto_indent_edits.is_empty() {
 4708                this.edit_with_autoindent(auto_indent_edits, cx);
 4709            }
 4710
 4711            let buffer = this.buffer.read(cx).snapshot(cx);
 4712            let new_selections = selection_info
 4713                .into_iter()
 4714                .map(|(extra_newline_inserted, new_selection)| {
 4715                    let mut cursor = new_selection.end.to_point(&buffer);
 4716                    if extra_newline_inserted {
 4717                        cursor.row -= 1;
 4718                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4719                    }
 4720                    new_selection.map(|_| cursor)
 4721                })
 4722                .collect();
 4723
 4724            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4725            this.refresh_edit_prediction(true, false, window, cx);
 4726        });
 4727    }
 4728
 4729    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4731
 4732        let buffer = self.buffer.read(cx);
 4733        let snapshot = buffer.snapshot(cx);
 4734
 4735        let mut edits = Vec::new();
 4736        let mut rows = Vec::new();
 4737
 4738        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4739            let cursor = selection.head();
 4740            let row = cursor.row;
 4741
 4742            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4743
 4744            let newline = "\n".to_string();
 4745            edits.push((start_of_line..start_of_line, newline));
 4746
 4747            rows.push(row + rows_inserted as u32);
 4748        }
 4749
 4750        self.transact(window, cx, |editor, window, cx| {
 4751            editor.edit(edits, cx);
 4752
 4753            editor.change_selections(Default::default(), window, cx, |s| {
 4754                let mut index = 0;
 4755                s.move_cursors_with(|map, _, _| {
 4756                    let row = rows[index];
 4757                    index += 1;
 4758
 4759                    let point = Point::new(row, 0);
 4760                    let boundary = map.next_line_boundary(point).1;
 4761                    let clipped = map.clip_point(boundary, Bias::Left);
 4762
 4763                    (clipped, SelectionGoal::None)
 4764                });
 4765            });
 4766
 4767            let mut indent_edits = Vec::new();
 4768            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4769            for row in rows {
 4770                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4771                for (row, indent) in indents {
 4772                    if indent.len == 0 {
 4773                        continue;
 4774                    }
 4775
 4776                    let text = match indent.kind {
 4777                        IndentKind::Space => " ".repeat(indent.len as usize),
 4778                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4779                    };
 4780                    let point = Point::new(row.0, 0);
 4781                    indent_edits.push((point..point, text));
 4782                }
 4783            }
 4784            editor.edit(indent_edits, cx);
 4785        });
 4786    }
 4787
 4788    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4790
 4791        let buffer = self.buffer.read(cx);
 4792        let snapshot = buffer.snapshot(cx);
 4793
 4794        let mut edits = Vec::new();
 4795        let mut rows = Vec::new();
 4796        let mut rows_inserted = 0;
 4797
 4798        for selection in self.selections.all_adjusted(cx) {
 4799            let cursor = selection.head();
 4800            let row = cursor.row;
 4801
 4802            let point = Point::new(row + 1, 0);
 4803            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4804
 4805            let newline = "\n".to_string();
 4806            edits.push((start_of_line..start_of_line, newline));
 4807
 4808            rows_inserted += 1;
 4809            rows.push(row + rows_inserted);
 4810        }
 4811
 4812        self.transact(window, cx, |editor, window, cx| {
 4813            editor.edit(edits, cx);
 4814
 4815            editor.change_selections(Default::default(), window, cx, |s| {
 4816                let mut index = 0;
 4817                s.move_cursors_with(|map, _, _| {
 4818                    let row = rows[index];
 4819                    index += 1;
 4820
 4821                    let point = Point::new(row, 0);
 4822                    let boundary = map.next_line_boundary(point).1;
 4823                    let clipped = map.clip_point(boundary, Bias::Left);
 4824
 4825                    (clipped, SelectionGoal::None)
 4826                });
 4827            });
 4828
 4829            let mut indent_edits = Vec::new();
 4830            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4831            for row in rows {
 4832                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4833                for (row, indent) in indents {
 4834                    if indent.len == 0 {
 4835                        continue;
 4836                    }
 4837
 4838                    let text = match indent.kind {
 4839                        IndentKind::Space => " ".repeat(indent.len as usize),
 4840                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4841                    };
 4842                    let point = Point::new(row.0, 0);
 4843                    indent_edits.push((point..point, text));
 4844                }
 4845            }
 4846            editor.edit(indent_edits, cx);
 4847        });
 4848    }
 4849
 4850    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4851        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4852            original_indent_columns: Vec::new(),
 4853        });
 4854        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4855    }
 4856
 4857    fn insert_with_autoindent_mode(
 4858        &mut self,
 4859        text: &str,
 4860        autoindent_mode: Option<AutoindentMode>,
 4861        window: &mut Window,
 4862        cx: &mut Context<Self>,
 4863    ) {
 4864        if self.read_only(cx) {
 4865            return;
 4866        }
 4867
 4868        let text: Arc<str> = text.into();
 4869        self.transact(window, cx, |this, window, cx| {
 4870            let old_selections = this.selections.all_adjusted(cx);
 4871            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4872                let anchors = {
 4873                    let snapshot = buffer.read(cx);
 4874                    old_selections
 4875                        .iter()
 4876                        .map(|s| {
 4877                            let anchor = snapshot.anchor_after(s.head());
 4878                            s.map(|_| anchor)
 4879                        })
 4880                        .collect::<Vec<_>>()
 4881                };
 4882                buffer.edit(
 4883                    old_selections
 4884                        .iter()
 4885                        .map(|s| (s.start..s.end, text.clone())),
 4886                    autoindent_mode,
 4887                    cx,
 4888                );
 4889                anchors
 4890            });
 4891
 4892            this.change_selections(Default::default(), window, cx, |s| {
 4893                s.select_anchors(selection_anchors);
 4894            });
 4895
 4896            cx.notify();
 4897        });
 4898    }
 4899
 4900    fn trigger_completion_on_input(
 4901        &mut self,
 4902        text: &str,
 4903        trigger_in_words: bool,
 4904        window: &mut Window,
 4905        cx: &mut Context<Self>,
 4906    ) {
 4907        let completions_source = self
 4908            .context_menu
 4909            .borrow()
 4910            .as_ref()
 4911            .and_then(|menu| match menu {
 4912                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4913                CodeContextMenu::CodeActions(_) => None,
 4914            });
 4915
 4916        match completions_source {
 4917            Some(CompletionsMenuSource::Words { .. }) => {
 4918                self.open_or_update_completions_menu(
 4919                    Some(CompletionsMenuSource::Words {
 4920                        ignore_threshold: false,
 4921                    }),
 4922                    None,
 4923                    window,
 4924                    cx,
 4925                );
 4926            }
 4927            Some(CompletionsMenuSource::Normal)
 4928            | Some(CompletionsMenuSource::SnippetChoices)
 4929            | None
 4930                if self.is_completion_trigger(
 4931                    text,
 4932                    trigger_in_words,
 4933                    completions_source.is_some(),
 4934                    cx,
 4935                ) =>
 4936            {
 4937                self.show_completions(
 4938                    &ShowCompletions {
 4939                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4940                    },
 4941                    window,
 4942                    cx,
 4943                )
 4944            }
 4945            _ => {
 4946                self.hide_context_menu(window, cx);
 4947            }
 4948        }
 4949    }
 4950
 4951    fn is_completion_trigger(
 4952        &self,
 4953        text: &str,
 4954        trigger_in_words: bool,
 4955        menu_is_open: bool,
 4956        cx: &mut Context<Self>,
 4957    ) -> bool {
 4958        let position = self.selections.newest_anchor().head();
 4959        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4960            return false;
 4961        };
 4962
 4963        if let Some(completion_provider) = &self.completion_provider {
 4964            completion_provider.is_completion_trigger(
 4965                &buffer,
 4966                position.text_anchor,
 4967                text,
 4968                trigger_in_words,
 4969                menu_is_open,
 4970                cx,
 4971            )
 4972        } else {
 4973            false
 4974        }
 4975    }
 4976
 4977    /// If any empty selections is touching the start of its innermost containing autoclose
 4978    /// region, expand it to select the brackets.
 4979    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4980        let selections = self.selections.all::<usize>(cx);
 4981        let buffer = self.buffer.read(cx).read(cx);
 4982        let new_selections = self
 4983            .selections_with_autoclose_regions(selections, &buffer)
 4984            .map(|(mut selection, region)| {
 4985                if !selection.is_empty() {
 4986                    return selection;
 4987                }
 4988
 4989                if let Some(region) = region {
 4990                    let mut range = region.range.to_offset(&buffer);
 4991                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4992                        range.start -= region.pair.start.len();
 4993                        if buffer.contains_str_at(range.start, &region.pair.start)
 4994                            && buffer.contains_str_at(range.end, &region.pair.end)
 4995                        {
 4996                            range.end += region.pair.end.len();
 4997                            selection.start = range.start;
 4998                            selection.end = range.end;
 4999
 5000                            return selection;
 5001                        }
 5002                    }
 5003                }
 5004
 5005                let always_treat_brackets_as_autoclosed = buffer
 5006                    .language_settings_at(selection.start, cx)
 5007                    .always_treat_brackets_as_autoclosed;
 5008
 5009                if !always_treat_brackets_as_autoclosed {
 5010                    return selection;
 5011                }
 5012
 5013                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5014                    for (pair, enabled) in scope.brackets() {
 5015                        if !enabled || !pair.close {
 5016                            continue;
 5017                        }
 5018
 5019                        if buffer.contains_str_at(selection.start, &pair.end) {
 5020                            let pair_start_len = pair.start.len();
 5021                            if buffer.contains_str_at(
 5022                                selection.start.saturating_sub(pair_start_len),
 5023                                &pair.start,
 5024                            ) {
 5025                                selection.start -= pair_start_len;
 5026                                selection.end += pair.end.len();
 5027
 5028                                return selection;
 5029                            }
 5030                        }
 5031                    }
 5032                }
 5033
 5034                selection
 5035            })
 5036            .collect();
 5037
 5038        drop(buffer);
 5039        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5040            selections.select(new_selections)
 5041        });
 5042    }
 5043
 5044    /// Iterate the given selections, and for each one, find the smallest surrounding
 5045    /// autoclose region. This uses the ordering of the selections and the autoclose
 5046    /// regions to avoid repeated comparisons.
 5047    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5048        &'a self,
 5049        selections: impl IntoIterator<Item = Selection<D>>,
 5050        buffer: &'a MultiBufferSnapshot,
 5051    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5052        let mut i = 0;
 5053        let mut regions = self.autoclose_regions.as_slice();
 5054        selections.into_iter().map(move |selection| {
 5055            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5056
 5057            let mut enclosing = None;
 5058            while let Some(pair_state) = regions.get(i) {
 5059                if pair_state.range.end.to_offset(buffer) < range.start {
 5060                    regions = &regions[i + 1..];
 5061                    i = 0;
 5062                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5063                    break;
 5064                } else {
 5065                    if pair_state.selection_id == selection.id {
 5066                        enclosing = Some(pair_state);
 5067                    }
 5068                    i += 1;
 5069                }
 5070            }
 5071
 5072            (selection, enclosing)
 5073        })
 5074    }
 5075
 5076    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5077    fn invalidate_autoclose_regions(
 5078        &mut self,
 5079        mut selections: &[Selection<Anchor>],
 5080        buffer: &MultiBufferSnapshot,
 5081    ) {
 5082        self.autoclose_regions.retain(|state| {
 5083            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5084                return false;
 5085            }
 5086
 5087            let mut i = 0;
 5088            while let Some(selection) = selections.get(i) {
 5089                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5090                    selections = &selections[1..];
 5091                    continue;
 5092                }
 5093                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5094                    break;
 5095                }
 5096                if selection.id == state.selection_id {
 5097                    return true;
 5098                } else {
 5099                    i += 1;
 5100                }
 5101            }
 5102            false
 5103        });
 5104    }
 5105
 5106    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5107        let offset = position.to_offset(buffer);
 5108        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5109        if offset > word_range.start && kind == Some(CharKind::Word) {
 5110            Some(
 5111                buffer
 5112                    .text_for_range(word_range.start..offset)
 5113                    .collect::<String>(),
 5114            )
 5115        } else {
 5116            None
 5117        }
 5118    }
 5119
 5120    pub fn toggle_inline_values(
 5121        &mut self,
 5122        _: &ToggleInlineValues,
 5123        _: &mut Window,
 5124        cx: &mut Context<Self>,
 5125    ) {
 5126        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5127
 5128        self.refresh_inline_values(cx);
 5129    }
 5130
 5131    pub fn toggle_inlay_hints(
 5132        &mut self,
 5133        _: &ToggleInlayHints,
 5134        _: &mut Window,
 5135        cx: &mut Context<Self>,
 5136    ) {
 5137        self.refresh_inlay_hints(
 5138            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5139            cx,
 5140        );
 5141    }
 5142
 5143    pub fn inlay_hints_enabled(&self) -> bool {
 5144        self.inlay_hint_cache.enabled
 5145    }
 5146
 5147    pub fn inline_values_enabled(&self) -> bool {
 5148        self.inline_value_cache.enabled
 5149    }
 5150
 5151    #[cfg(any(test, feature = "test-support"))]
 5152    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5153        self.display_map
 5154            .read(cx)
 5155            .current_inlays()
 5156            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5157            .cloned()
 5158            .collect()
 5159    }
 5160
 5161    #[cfg(any(test, feature = "test-support"))]
 5162    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5163        self.display_map
 5164            .read(cx)
 5165            .current_inlays()
 5166            .cloned()
 5167            .collect()
 5168    }
 5169
 5170    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5171        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5172            return;
 5173        }
 5174
 5175        let reason_description = reason.description();
 5176        let ignore_debounce = matches!(
 5177            reason,
 5178            InlayHintRefreshReason::SettingsChange(_)
 5179                | InlayHintRefreshReason::Toggle(_)
 5180                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5181                | InlayHintRefreshReason::ModifiersChanged(_)
 5182        );
 5183        let (invalidate_cache, required_languages) = match reason {
 5184            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5185                match self.inlay_hint_cache.modifiers_override(enabled) {
 5186                    Some(enabled) => {
 5187                        if enabled {
 5188                            (InvalidationStrategy::RefreshRequested, None)
 5189                        } else {
 5190                            self.splice_inlays(
 5191                                &self
 5192                                    .visible_inlay_hints(cx)
 5193                                    .iter()
 5194                                    .map(|inlay| inlay.id)
 5195                                    .collect::<Vec<InlayId>>(),
 5196                                Vec::new(),
 5197                                cx,
 5198                            );
 5199                            return;
 5200                        }
 5201                    }
 5202                    None => return,
 5203                }
 5204            }
 5205            InlayHintRefreshReason::Toggle(enabled) => {
 5206                if self.inlay_hint_cache.toggle(enabled) {
 5207                    if enabled {
 5208                        (InvalidationStrategy::RefreshRequested, None)
 5209                    } else {
 5210                        self.splice_inlays(
 5211                            &self
 5212                                .visible_inlay_hints(cx)
 5213                                .iter()
 5214                                .map(|inlay| inlay.id)
 5215                                .collect::<Vec<InlayId>>(),
 5216                            Vec::new(),
 5217                            cx,
 5218                        );
 5219                        return;
 5220                    }
 5221                } else {
 5222                    return;
 5223                }
 5224            }
 5225            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5226                match self.inlay_hint_cache.update_settings(
 5227                    &self.buffer,
 5228                    new_settings,
 5229                    self.visible_inlay_hints(cx),
 5230                    cx,
 5231                ) {
 5232                    ControlFlow::Break(Some(InlaySplice {
 5233                        to_remove,
 5234                        to_insert,
 5235                    })) => {
 5236                        self.splice_inlays(&to_remove, to_insert, cx);
 5237                        return;
 5238                    }
 5239                    ControlFlow::Break(None) => return,
 5240                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5241                }
 5242            }
 5243            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5244                if let Some(InlaySplice {
 5245                    to_remove,
 5246                    to_insert,
 5247                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5248                {
 5249                    self.splice_inlays(&to_remove, to_insert, cx);
 5250                }
 5251                self.display_map.update(cx, |display_map, _| {
 5252                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5253                });
 5254                return;
 5255            }
 5256            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5257            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5258                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5259            }
 5260            InlayHintRefreshReason::RefreshRequested => {
 5261                (InvalidationStrategy::RefreshRequested, None)
 5262            }
 5263        };
 5264
 5265        if let Some(InlaySplice {
 5266            to_remove,
 5267            to_insert,
 5268        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5269            reason_description,
 5270            self.visible_excerpts(required_languages.as_ref(), cx),
 5271            invalidate_cache,
 5272            ignore_debounce,
 5273            cx,
 5274        ) {
 5275            self.splice_inlays(&to_remove, to_insert, cx);
 5276        }
 5277    }
 5278
 5279    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5280        self.display_map
 5281            .read(cx)
 5282            .current_inlays()
 5283            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5284            .cloned()
 5285            .collect()
 5286    }
 5287
 5288    pub fn visible_excerpts(
 5289        &self,
 5290        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5291        cx: &mut Context<Editor>,
 5292    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5293        let Some(project) = self.project() else {
 5294            return HashMap::default();
 5295        };
 5296        let project = project.read(cx);
 5297        let multi_buffer = self.buffer().read(cx);
 5298        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5299        let multi_buffer_visible_start = self
 5300            .scroll_manager
 5301            .anchor()
 5302            .anchor
 5303            .to_point(&multi_buffer_snapshot);
 5304        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5305            multi_buffer_visible_start
 5306                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5307            Bias::Left,
 5308        );
 5309        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5310        multi_buffer_snapshot
 5311            .range_to_buffer_ranges(multi_buffer_visible_range)
 5312            .into_iter()
 5313            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5314            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5315                let buffer_file = project::File::from_dyn(buffer.file())?;
 5316                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5317                let worktree_entry = buffer_worktree
 5318                    .read(cx)
 5319                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5320                if worktree_entry.is_ignored {
 5321                    return None;
 5322                }
 5323
 5324                let language = buffer.language()?;
 5325                if let Some(restrict_to_languages) = restrict_to_languages
 5326                    && !restrict_to_languages.contains(language)
 5327                {
 5328                    return None;
 5329                }
 5330                Some((
 5331                    excerpt_id,
 5332                    (
 5333                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5334                        buffer.version().clone(),
 5335                        excerpt_visible_range,
 5336                    ),
 5337                ))
 5338            })
 5339            .collect()
 5340    }
 5341
 5342    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5343        TextLayoutDetails {
 5344            text_system: window.text_system().clone(),
 5345            editor_style: self.style.clone().unwrap(),
 5346            rem_size: window.rem_size(),
 5347            scroll_anchor: self.scroll_manager.anchor(),
 5348            visible_rows: self.visible_line_count(),
 5349            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5350        }
 5351    }
 5352
 5353    pub fn splice_inlays(
 5354        &self,
 5355        to_remove: &[InlayId],
 5356        to_insert: Vec<Inlay>,
 5357        cx: &mut Context<Self>,
 5358    ) {
 5359        self.display_map.update(cx, |display_map, cx| {
 5360            display_map.splice_inlays(to_remove, to_insert, cx)
 5361        });
 5362        cx.notify();
 5363    }
 5364
 5365    fn trigger_on_type_formatting(
 5366        &self,
 5367        input: String,
 5368        window: &mut Window,
 5369        cx: &mut Context<Self>,
 5370    ) -> Option<Task<Result<()>>> {
 5371        if input.len() != 1 {
 5372            return None;
 5373        }
 5374
 5375        let project = self.project()?;
 5376        let position = self.selections.newest_anchor().head();
 5377        let (buffer, buffer_position) = self
 5378            .buffer
 5379            .read(cx)
 5380            .text_anchor_for_position(position, cx)?;
 5381
 5382        let settings = language_settings::language_settings(
 5383            buffer
 5384                .read(cx)
 5385                .language_at(buffer_position)
 5386                .map(|l| l.name()),
 5387            buffer.read(cx).file(),
 5388            cx,
 5389        );
 5390        if !settings.use_on_type_format {
 5391            return None;
 5392        }
 5393
 5394        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5395        // hence we do LSP request & edit on host side only — add formats to host's history.
 5396        let push_to_lsp_host_history = true;
 5397        // If this is not the host, append its history with new edits.
 5398        let push_to_client_history = project.read(cx).is_via_collab();
 5399
 5400        let on_type_formatting = project.update(cx, |project, cx| {
 5401            project.on_type_format(
 5402                buffer.clone(),
 5403                buffer_position,
 5404                input,
 5405                push_to_lsp_host_history,
 5406                cx,
 5407            )
 5408        });
 5409        Some(cx.spawn_in(window, async move |editor, cx| {
 5410            if let Some(transaction) = on_type_formatting.await? {
 5411                if push_to_client_history {
 5412                    buffer
 5413                        .update(cx, |buffer, _| {
 5414                            buffer.push_transaction(transaction, Instant::now());
 5415                            buffer.finalize_last_transaction();
 5416                        })
 5417                        .ok();
 5418                }
 5419                editor.update(cx, |editor, cx| {
 5420                    editor.refresh_document_highlights(cx);
 5421                })?;
 5422            }
 5423            Ok(())
 5424        }))
 5425    }
 5426
 5427    pub fn show_word_completions(
 5428        &mut self,
 5429        _: &ShowWordCompletions,
 5430        window: &mut Window,
 5431        cx: &mut Context<Self>,
 5432    ) {
 5433        self.open_or_update_completions_menu(
 5434            Some(CompletionsMenuSource::Words {
 5435                ignore_threshold: true,
 5436            }),
 5437            None,
 5438            window,
 5439            cx,
 5440        );
 5441    }
 5442
 5443    pub fn show_completions(
 5444        &mut self,
 5445        options: &ShowCompletions,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) {
 5449        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5450    }
 5451
 5452    fn open_or_update_completions_menu(
 5453        &mut self,
 5454        requested_source: Option<CompletionsMenuSource>,
 5455        trigger: Option<&str>,
 5456        window: &mut Window,
 5457        cx: &mut Context<Self>,
 5458    ) {
 5459        if self.pending_rename.is_some() {
 5460            return;
 5461        }
 5462
 5463        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5464
 5465        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5466        // inserted and selected. To handle that case, the start of the selection is used so that
 5467        // the menu starts with all choices.
 5468        let position = self
 5469            .selections
 5470            .newest_anchor()
 5471            .start
 5472            .bias_right(&multibuffer_snapshot);
 5473        if position.diff_base_anchor.is_some() {
 5474            return;
 5475        }
 5476        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5477        let Some(buffer) = buffer_position
 5478            .buffer_id
 5479            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5480        else {
 5481            return;
 5482        };
 5483        let buffer_snapshot = buffer.read(cx).snapshot();
 5484
 5485        let query: Option<Arc<String>> =
 5486            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5487                .map(|query| query.into());
 5488
 5489        drop(multibuffer_snapshot);
 5490
 5491        // Hide the current completions menu when query is empty. Without this, cached
 5492        // completions from before the trigger char may be reused (#32774).
 5493        if query.is_none() {
 5494            let menu_is_open = matches!(
 5495                self.context_menu.borrow().as_ref(),
 5496                Some(CodeContextMenu::Completions(_))
 5497            );
 5498            if menu_is_open {
 5499                self.hide_context_menu(window, cx);
 5500            }
 5501        }
 5502
 5503        let mut ignore_word_threshold = false;
 5504        let provider = match requested_source {
 5505            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5506            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5507                ignore_word_threshold = ignore_threshold;
 5508                None
 5509            }
 5510            Some(CompletionsMenuSource::SnippetChoices) => {
 5511                log::error!("bug: SnippetChoices requested_source is not handled");
 5512                None
 5513            }
 5514        };
 5515
 5516        let sort_completions = provider
 5517            .as_ref()
 5518            .is_some_and(|provider| provider.sort_completions());
 5519
 5520        let filter_completions = provider
 5521            .as_ref()
 5522            .is_none_or(|provider| provider.filter_completions());
 5523
 5524        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5525            if filter_completions {
 5526                menu.filter(query.clone(), provider.clone(), window, cx);
 5527            }
 5528            // When `is_incomplete` is false, no need to re-query completions when the current query
 5529            // is a suffix of the initial query.
 5530            if !menu.is_incomplete {
 5531                // If the new query is a suffix of the old query (typing more characters) and
 5532                // the previous result was complete, the existing completions can be filtered.
 5533                //
 5534                // Note that this is always true for snippet completions.
 5535                let query_matches = match (&menu.initial_query, &query) {
 5536                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5537                    (None, _) => true,
 5538                    _ => false,
 5539                };
 5540                if query_matches {
 5541                    let position_matches = if menu.initial_position == position {
 5542                        true
 5543                    } else {
 5544                        let snapshot = self.buffer.read(cx).read(cx);
 5545                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5546                    };
 5547                    if position_matches {
 5548                        return;
 5549                    }
 5550                }
 5551            }
 5552        };
 5553
 5554        let trigger_kind = match trigger {
 5555            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5556                CompletionTriggerKind::TRIGGER_CHARACTER
 5557            }
 5558            _ => CompletionTriggerKind::INVOKED,
 5559        };
 5560        let completion_context = CompletionContext {
 5561            trigger_character: trigger.and_then(|trigger| {
 5562                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5563                    Some(String::from(trigger))
 5564                } else {
 5565                    None
 5566                }
 5567            }),
 5568            trigger_kind,
 5569        };
 5570
 5571        let Anchor {
 5572            excerpt_id: buffer_excerpt_id,
 5573            text_anchor: buffer_position,
 5574            ..
 5575        } = buffer_position;
 5576
 5577        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5578            buffer_snapshot.surrounding_word(buffer_position, false)
 5579        {
 5580            let word_to_exclude = buffer_snapshot
 5581                .text_for_range(word_range.clone())
 5582                .collect::<String>();
 5583            (
 5584                buffer_snapshot.anchor_before(word_range.start)
 5585                    ..buffer_snapshot.anchor_after(buffer_position),
 5586                Some(word_to_exclude),
 5587            )
 5588        } else {
 5589            (buffer_position..buffer_position, None)
 5590        };
 5591
 5592        let language = buffer_snapshot
 5593            .language_at(buffer_position)
 5594            .map(|language| language.name());
 5595
 5596        let completion_settings =
 5597            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5598
 5599        let show_completion_documentation = buffer_snapshot
 5600            .settings_at(buffer_position, cx)
 5601            .show_completion_documentation;
 5602
 5603        // The document can be large, so stay in reasonable bounds when searching for words,
 5604        // otherwise completion pop-up might be slow to appear.
 5605        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5606        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5607        let min_word_search = buffer_snapshot.clip_point(
 5608            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5609            Bias::Left,
 5610        );
 5611        let max_word_search = buffer_snapshot.clip_point(
 5612            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5613            Bias::Right,
 5614        );
 5615        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5616            ..buffer_snapshot.point_to_offset(max_word_search);
 5617
 5618        let skip_digits = query
 5619            .as_ref()
 5620            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5621
 5622        let omit_word_completions = !self.word_completions_enabled
 5623            || (!ignore_word_threshold
 5624                && match &query {
 5625                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5626                    None => completion_settings.words_min_length != 0,
 5627                });
 5628
 5629        let (mut words, provider_responses) = match &provider {
 5630            Some(provider) => {
 5631                let provider_responses = provider.completions(
 5632                    buffer_excerpt_id,
 5633                    &buffer,
 5634                    buffer_position,
 5635                    completion_context,
 5636                    window,
 5637                    cx,
 5638                );
 5639
 5640                let words = match (omit_word_completions, completion_settings.words) {
 5641                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5642                        Task::ready(BTreeMap::default())
 5643                    }
 5644                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5645                        .background_spawn(async move {
 5646                            buffer_snapshot.words_in_range(WordsQuery {
 5647                                fuzzy_contents: None,
 5648                                range: word_search_range,
 5649                                skip_digits,
 5650                            })
 5651                        }),
 5652                };
 5653
 5654                (words, provider_responses)
 5655            }
 5656            None => {
 5657                let words = if omit_word_completions {
 5658                    Task::ready(BTreeMap::default())
 5659                } else {
 5660                    cx.background_spawn(async move {
 5661                        buffer_snapshot.words_in_range(WordsQuery {
 5662                            fuzzy_contents: None,
 5663                            range: word_search_range,
 5664                            skip_digits,
 5665                        })
 5666                    })
 5667                };
 5668                (words, Task::ready(Ok(Vec::new())))
 5669            }
 5670        };
 5671
 5672        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5673
 5674        let id = post_inc(&mut self.next_completion_id);
 5675        let task = cx.spawn_in(window, async move |editor, cx| {
 5676            let Ok(()) = editor.update(cx, |this, _| {
 5677                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5678            }) else {
 5679                return;
 5680            };
 5681
 5682            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5683            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5684            let mut completions = Vec::new();
 5685            let mut is_incomplete = false;
 5686            let mut display_options: Option<CompletionDisplayOptions> = None;
 5687            if let Some(provider_responses) = provider_responses.await.log_err()
 5688                && !provider_responses.is_empty()
 5689            {
 5690                for response in provider_responses {
 5691                    completions.extend(response.completions);
 5692                    is_incomplete = is_incomplete || response.is_incomplete;
 5693                    match display_options.as_mut() {
 5694                        None => {
 5695                            display_options = Some(response.display_options);
 5696                        }
 5697                        Some(options) => options.merge(&response.display_options),
 5698                    }
 5699                }
 5700                if completion_settings.words == WordsCompletionMode::Fallback {
 5701                    words = Task::ready(BTreeMap::default());
 5702                }
 5703            }
 5704            let display_options = display_options.unwrap_or_default();
 5705
 5706            let mut words = words.await;
 5707            if let Some(word_to_exclude) = &word_to_exclude {
 5708                words.remove(word_to_exclude);
 5709            }
 5710            for lsp_completion in &completions {
 5711                words.remove(&lsp_completion.new_text);
 5712            }
 5713            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5714                replace_range: word_replace_range.clone(),
 5715                new_text: word.clone(),
 5716                label: CodeLabel::plain(word, None),
 5717                icon_path: None,
 5718                documentation: None,
 5719                source: CompletionSource::BufferWord {
 5720                    word_range,
 5721                    resolved: false,
 5722                },
 5723                insert_text_mode: Some(InsertTextMode::AS_IS),
 5724                confirm: None,
 5725            }));
 5726
 5727            let menu = if completions.is_empty() {
 5728                None
 5729            } else {
 5730                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5731                    let languages = editor
 5732                        .workspace
 5733                        .as_ref()
 5734                        .and_then(|(workspace, _)| workspace.upgrade())
 5735                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5736                    let menu = CompletionsMenu::new(
 5737                        id,
 5738                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5739                        sort_completions,
 5740                        show_completion_documentation,
 5741                        position,
 5742                        query.clone(),
 5743                        is_incomplete,
 5744                        buffer.clone(),
 5745                        completions.into(),
 5746                        display_options,
 5747                        snippet_sort_order,
 5748                        languages,
 5749                        language,
 5750                        cx,
 5751                    );
 5752
 5753                    let query = if filter_completions { query } else { None };
 5754                    let matches_task = if let Some(query) = query {
 5755                        menu.do_async_filtering(query, cx)
 5756                    } else {
 5757                        Task::ready(menu.unfiltered_matches())
 5758                    };
 5759                    (menu, matches_task)
 5760                }) else {
 5761                    return;
 5762                };
 5763
 5764                let matches = matches_task.await;
 5765
 5766                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5767                    // Newer menu already set, so exit.
 5768                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5769                        editor.context_menu.borrow().as_ref()
 5770                        && prev_menu.id > id
 5771                    {
 5772                        return;
 5773                    };
 5774
 5775                    // Only valid to take prev_menu because it the new menu is immediately set
 5776                    // below, or the menu is hidden.
 5777                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5778                        editor.context_menu.borrow_mut().take()
 5779                    {
 5780                        let position_matches =
 5781                            if prev_menu.initial_position == menu.initial_position {
 5782                                true
 5783                            } else {
 5784                                let snapshot = editor.buffer.read(cx).read(cx);
 5785                                prev_menu.initial_position.to_offset(&snapshot)
 5786                                    == menu.initial_position.to_offset(&snapshot)
 5787                            };
 5788                        if position_matches {
 5789                            // Preserve markdown cache before `set_filter_results` because it will
 5790                            // try to populate the documentation cache.
 5791                            menu.preserve_markdown_cache(prev_menu);
 5792                        }
 5793                    };
 5794
 5795                    menu.set_filter_results(matches, provider, window, cx);
 5796                }) else {
 5797                    return;
 5798                };
 5799
 5800                menu.visible().then_some(menu)
 5801            };
 5802
 5803            editor
 5804                .update_in(cx, |editor, window, cx| {
 5805                    if editor.focus_handle.is_focused(window)
 5806                        && let Some(menu) = menu
 5807                    {
 5808                        *editor.context_menu.borrow_mut() =
 5809                            Some(CodeContextMenu::Completions(menu));
 5810
 5811                        crate::hover_popover::hide_hover(editor, cx);
 5812                        if editor.show_edit_predictions_in_menu() {
 5813                            editor.update_visible_edit_prediction(window, cx);
 5814                        } else {
 5815                            editor.discard_edit_prediction(false, cx);
 5816                        }
 5817
 5818                        cx.notify();
 5819                        return;
 5820                    }
 5821
 5822                    if editor.completion_tasks.len() <= 1 {
 5823                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5824                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5825                        // If it was already hidden and we don't show edit predictions in the menu,
 5826                        // we should also show the edit prediction when available.
 5827                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5828                            editor.update_visible_edit_prediction(window, cx);
 5829                        }
 5830                    }
 5831                })
 5832                .ok();
 5833        });
 5834
 5835        self.completion_tasks.push((id, task));
 5836    }
 5837
 5838    #[cfg(feature = "test-support")]
 5839    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5840        let menu = self.context_menu.borrow();
 5841        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5842            let completions = menu.completions.borrow();
 5843            Some(completions.to_vec())
 5844        } else {
 5845            None
 5846        }
 5847    }
 5848
 5849    pub fn with_completions_menu_matching_id<R>(
 5850        &self,
 5851        id: CompletionId,
 5852        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5853    ) -> R {
 5854        let mut context_menu = self.context_menu.borrow_mut();
 5855        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5856            return f(None);
 5857        };
 5858        if completions_menu.id != id {
 5859            return f(None);
 5860        }
 5861        f(Some(completions_menu))
 5862    }
 5863
 5864    pub fn confirm_completion(
 5865        &mut self,
 5866        action: &ConfirmCompletion,
 5867        window: &mut Window,
 5868        cx: &mut Context<Self>,
 5869    ) -> Option<Task<Result<()>>> {
 5870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5871        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5872    }
 5873
 5874    pub fn confirm_completion_insert(
 5875        &mut self,
 5876        _: &ConfirmCompletionInsert,
 5877        window: &mut Window,
 5878        cx: &mut Context<Self>,
 5879    ) -> Option<Task<Result<()>>> {
 5880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5881        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5882    }
 5883
 5884    pub fn confirm_completion_replace(
 5885        &mut self,
 5886        _: &ConfirmCompletionReplace,
 5887        window: &mut Window,
 5888        cx: &mut Context<Self>,
 5889    ) -> Option<Task<Result<()>>> {
 5890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5891        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5892    }
 5893
 5894    pub fn compose_completion(
 5895        &mut self,
 5896        action: &ComposeCompletion,
 5897        window: &mut Window,
 5898        cx: &mut Context<Self>,
 5899    ) -> Option<Task<Result<()>>> {
 5900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5901        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5902    }
 5903
 5904    fn do_completion(
 5905        &mut self,
 5906        item_ix: Option<usize>,
 5907        intent: CompletionIntent,
 5908        window: &mut Window,
 5909        cx: &mut Context<Editor>,
 5910    ) -> Option<Task<Result<()>>> {
 5911        use language::ToOffset as _;
 5912
 5913        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5914        else {
 5915            return None;
 5916        };
 5917
 5918        let candidate_id = {
 5919            let entries = completions_menu.entries.borrow();
 5920            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5921            if self.show_edit_predictions_in_menu() {
 5922                self.discard_edit_prediction(true, cx);
 5923            }
 5924            mat.candidate_id
 5925        };
 5926
 5927        let completion = completions_menu
 5928            .completions
 5929            .borrow()
 5930            .get(candidate_id)?
 5931            .clone();
 5932        cx.stop_propagation();
 5933
 5934        let buffer_handle = completions_menu.buffer.clone();
 5935
 5936        let CompletionEdit {
 5937            new_text,
 5938            snippet,
 5939            replace_range,
 5940        } = process_completion_for_edit(
 5941            &completion,
 5942            intent,
 5943            &buffer_handle,
 5944            &completions_menu.initial_position.text_anchor,
 5945            cx,
 5946        );
 5947
 5948        let buffer = buffer_handle.read(cx);
 5949        let snapshot = self.buffer.read(cx).snapshot(cx);
 5950        let newest_anchor = self.selections.newest_anchor();
 5951        let replace_range_multibuffer = {
 5952            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5953            let multibuffer_anchor = snapshot
 5954                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5955                .unwrap()
 5956                ..snapshot
 5957                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5958                    .unwrap();
 5959            multibuffer_anchor.start.to_offset(&snapshot)
 5960                ..multibuffer_anchor.end.to_offset(&snapshot)
 5961        };
 5962        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5963            return None;
 5964        }
 5965
 5966        let old_text = buffer
 5967            .text_for_range(replace_range.clone())
 5968            .collect::<String>();
 5969        let lookbehind = newest_anchor
 5970            .start
 5971            .text_anchor
 5972            .to_offset(buffer)
 5973            .saturating_sub(replace_range.start);
 5974        let lookahead = replace_range
 5975            .end
 5976            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5977        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5978        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5979
 5980        let selections = self.selections.all::<usize>(cx);
 5981        let mut ranges = Vec::new();
 5982        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5983
 5984        for selection in &selections {
 5985            let range = if selection.id == newest_anchor.id {
 5986                replace_range_multibuffer.clone()
 5987            } else {
 5988                let mut range = selection.range();
 5989
 5990                // if prefix is present, don't duplicate it
 5991                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5992                    range.start = range.start.saturating_sub(lookbehind);
 5993
 5994                    // if suffix is also present, mimic the newest cursor and replace it
 5995                    if selection.id != newest_anchor.id
 5996                        && snapshot.contains_str_at(range.end, suffix)
 5997                    {
 5998                        range.end += lookahead;
 5999                    }
 6000                }
 6001                range
 6002            };
 6003
 6004            ranges.push(range.clone());
 6005
 6006            if !self.linked_edit_ranges.is_empty() {
 6007                let start_anchor = snapshot.anchor_before(range.start);
 6008                let end_anchor = snapshot.anchor_after(range.end);
 6009                if let Some(ranges) = self
 6010                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6011                {
 6012                    for (buffer, edits) in ranges {
 6013                        linked_edits
 6014                            .entry(buffer.clone())
 6015                            .or_default()
 6016                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6017                    }
 6018                }
 6019            }
 6020        }
 6021
 6022        let common_prefix_len = old_text
 6023            .chars()
 6024            .zip(new_text.chars())
 6025            .take_while(|(a, b)| a == b)
 6026            .map(|(a, _)| a.len_utf8())
 6027            .sum::<usize>();
 6028
 6029        cx.emit(EditorEvent::InputHandled {
 6030            utf16_range_to_replace: None,
 6031            text: new_text[common_prefix_len..].into(),
 6032        });
 6033
 6034        self.transact(window, cx, |editor, window, cx| {
 6035            if let Some(mut snippet) = snippet {
 6036                snippet.text = new_text.to_string();
 6037                editor
 6038                    .insert_snippet(&ranges, snippet, window, cx)
 6039                    .log_err();
 6040            } else {
 6041                editor.buffer.update(cx, |multi_buffer, cx| {
 6042                    let auto_indent = match completion.insert_text_mode {
 6043                        Some(InsertTextMode::AS_IS) => None,
 6044                        _ => editor.autoindent_mode.clone(),
 6045                    };
 6046                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6047                    multi_buffer.edit(edits, auto_indent, cx);
 6048                });
 6049            }
 6050            for (buffer, edits) in linked_edits {
 6051                buffer.update(cx, |buffer, cx| {
 6052                    let snapshot = buffer.snapshot();
 6053                    let edits = edits
 6054                        .into_iter()
 6055                        .map(|(range, text)| {
 6056                            use text::ToPoint as TP;
 6057                            let end_point = TP::to_point(&range.end, &snapshot);
 6058                            let start_point = TP::to_point(&range.start, &snapshot);
 6059                            (start_point..end_point, text)
 6060                        })
 6061                        .sorted_by_key(|(range, _)| range.start);
 6062                    buffer.edit(edits, None, cx);
 6063                })
 6064            }
 6065
 6066            editor.refresh_edit_prediction(true, false, window, cx);
 6067        });
 6068        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6069
 6070        let show_new_completions_on_confirm = completion
 6071            .confirm
 6072            .as_ref()
 6073            .is_some_and(|confirm| confirm(intent, window, cx));
 6074        if show_new_completions_on_confirm {
 6075            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6076        }
 6077
 6078        let provider = self.completion_provider.as_ref()?;
 6079        drop(completion);
 6080        let apply_edits = provider.apply_additional_edits_for_completion(
 6081            buffer_handle,
 6082            completions_menu.completions.clone(),
 6083            candidate_id,
 6084            true,
 6085            cx,
 6086        );
 6087
 6088        let editor_settings = EditorSettings::get_global(cx);
 6089        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6090            // After the code completion is finished, users often want to know what signatures are needed.
 6091            // so we should automatically call signature_help
 6092            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6093        }
 6094
 6095        Some(cx.foreground_executor().spawn(async move {
 6096            apply_edits.await?;
 6097            Ok(())
 6098        }))
 6099    }
 6100
 6101    pub fn toggle_code_actions(
 6102        &mut self,
 6103        action: &ToggleCodeActions,
 6104        window: &mut Window,
 6105        cx: &mut Context<Self>,
 6106    ) {
 6107        let quick_launch = action.quick_launch;
 6108        let mut context_menu = self.context_menu.borrow_mut();
 6109        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6110            if code_actions.deployed_from == action.deployed_from {
 6111                // Toggle if we're selecting the same one
 6112                *context_menu = None;
 6113                cx.notify();
 6114                return;
 6115            } else {
 6116                // Otherwise, clear it and start a new one
 6117                *context_menu = None;
 6118                cx.notify();
 6119            }
 6120        }
 6121        drop(context_menu);
 6122        let snapshot = self.snapshot(window, cx);
 6123        let deployed_from = action.deployed_from.clone();
 6124        let action = action.clone();
 6125        self.completion_tasks.clear();
 6126        self.discard_edit_prediction(false, cx);
 6127
 6128        let multibuffer_point = match &action.deployed_from {
 6129            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6130                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6131            }
 6132            _ => self.selections.newest::<Point>(cx).head(),
 6133        };
 6134        let Some((buffer, buffer_row)) = snapshot
 6135            .buffer_snapshot
 6136            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6137            .and_then(|(buffer_snapshot, range)| {
 6138                self.buffer()
 6139                    .read(cx)
 6140                    .buffer(buffer_snapshot.remote_id())
 6141                    .map(|buffer| (buffer, range.start.row))
 6142            })
 6143        else {
 6144            return;
 6145        };
 6146        let buffer_id = buffer.read(cx).remote_id();
 6147        let tasks = self
 6148            .tasks
 6149            .get(&(buffer_id, buffer_row))
 6150            .map(|t| Arc::new(t.to_owned()));
 6151
 6152        if !self.focus_handle.is_focused(window) {
 6153            return;
 6154        }
 6155        let project = self.project.clone();
 6156
 6157        let code_actions_task = match deployed_from {
 6158            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6159            _ => self.code_actions(buffer_row, window, cx),
 6160        };
 6161
 6162        let runnable_task = match deployed_from {
 6163            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6164            _ => {
 6165                let mut task_context_task = Task::ready(None);
 6166                if let Some(tasks) = &tasks
 6167                    && let Some(project) = project
 6168                {
 6169                    task_context_task =
 6170                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6171                }
 6172
 6173                cx.spawn_in(window, {
 6174                    let buffer = buffer.clone();
 6175                    async move |editor, cx| {
 6176                        let task_context = task_context_task.await;
 6177
 6178                        let resolved_tasks =
 6179                            tasks
 6180                                .zip(task_context.clone())
 6181                                .map(|(tasks, task_context)| ResolvedTasks {
 6182                                    templates: tasks.resolve(&task_context).collect(),
 6183                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6184                                        multibuffer_point.row,
 6185                                        tasks.column,
 6186                                    )),
 6187                                });
 6188                        let debug_scenarios = editor
 6189                            .update(cx, |editor, cx| {
 6190                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6191                            })?
 6192                            .await;
 6193                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6194                    }
 6195                })
 6196            }
 6197        };
 6198
 6199        cx.spawn_in(window, async move |editor, cx| {
 6200            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6201            let code_actions = code_actions_task.await;
 6202            let spawn_straight_away = quick_launch
 6203                && resolved_tasks
 6204                    .as_ref()
 6205                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6206                && code_actions
 6207                    .as_ref()
 6208                    .is_none_or(|actions| actions.is_empty())
 6209                && debug_scenarios.is_empty();
 6210
 6211            editor.update_in(cx, |editor, window, cx| {
 6212                crate::hover_popover::hide_hover(editor, cx);
 6213                let actions = CodeActionContents::new(
 6214                    resolved_tasks,
 6215                    code_actions,
 6216                    debug_scenarios,
 6217                    task_context.unwrap_or_default(),
 6218                );
 6219
 6220                // Don't show the menu if there are no actions available
 6221                if actions.is_empty() {
 6222                    cx.notify();
 6223                    return Task::ready(Ok(()));
 6224                }
 6225
 6226                *editor.context_menu.borrow_mut() =
 6227                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6228                        buffer,
 6229                        actions,
 6230                        selected_item: Default::default(),
 6231                        scroll_handle: UniformListScrollHandle::default(),
 6232                        deployed_from,
 6233                    }));
 6234                cx.notify();
 6235                if spawn_straight_away
 6236                    && let Some(task) = editor.confirm_code_action(
 6237                        &ConfirmCodeAction { item_ix: Some(0) },
 6238                        window,
 6239                        cx,
 6240                    )
 6241                {
 6242                    return task;
 6243                }
 6244
 6245                Task::ready(Ok(()))
 6246            })
 6247        })
 6248        .detach_and_log_err(cx);
 6249    }
 6250
 6251    fn debug_scenarios(
 6252        &mut self,
 6253        resolved_tasks: &Option<ResolvedTasks>,
 6254        buffer: &Entity<Buffer>,
 6255        cx: &mut App,
 6256    ) -> Task<Vec<task::DebugScenario>> {
 6257        maybe!({
 6258            let project = self.project()?;
 6259            let dap_store = project.read(cx).dap_store();
 6260            let mut scenarios = vec![];
 6261            let resolved_tasks = resolved_tasks.as_ref()?;
 6262            let buffer = buffer.read(cx);
 6263            let language = buffer.language()?;
 6264            let file = buffer.file();
 6265            let debug_adapter = language_settings(language.name().into(), file, cx)
 6266                .debuggers
 6267                .first()
 6268                .map(SharedString::from)
 6269                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6270
 6271            dap_store.update(cx, |dap_store, cx| {
 6272                for (_, task) in &resolved_tasks.templates {
 6273                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6274                        task.original_task().clone(),
 6275                        debug_adapter.clone().into(),
 6276                        task.display_label().to_owned().into(),
 6277                        cx,
 6278                    );
 6279                    scenarios.push(maybe_scenario);
 6280                }
 6281            });
 6282            Some(cx.background_spawn(async move {
 6283                futures::future::join_all(scenarios)
 6284                    .await
 6285                    .into_iter()
 6286                    .flatten()
 6287                    .collect::<Vec<_>>()
 6288            }))
 6289        })
 6290        .unwrap_or_else(|| Task::ready(vec![]))
 6291    }
 6292
 6293    fn code_actions(
 6294        &mut self,
 6295        buffer_row: u32,
 6296        window: &mut Window,
 6297        cx: &mut Context<Self>,
 6298    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6299        let mut task = self.code_actions_task.take();
 6300        cx.spawn_in(window, async move |editor, cx| {
 6301            while let Some(prev_task) = task {
 6302                prev_task.await.log_err();
 6303                task = editor
 6304                    .update(cx, |this, _| this.code_actions_task.take())
 6305                    .ok()?;
 6306            }
 6307
 6308            editor
 6309                .update(cx, |editor, cx| {
 6310                    editor
 6311                        .available_code_actions
 6312                        .clone()
 6313                        .and_then(|(location, code_actions)| {
 6314                            let snapshot = location.buffer.read(cx).snapshot();
 6315                            let point_range = location.range.to_point(&snapshot);
 6316                            let point_range = point_range.start.row..=point_range.end.row;
 6317                            if point_range.contains(&buffer_row) {
 6318                                Some(code_actions)
 6319                            } else {
 6320                                None
 6321                            }
 6322                        })
 6323                })
 6324                .ok()
 6325                .flatten()
 6326        })
 6327    }
 6328
 6329    pub fn confirm_code_action(
 6330        &mut self,
 6331        action: &ConfirmCodeAction,
 6332        window: &mut Window,
 6333        cx: &mut Context<Self>,
 6334    ) -> Option<Task<Result<()>>> {
 6335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6336
 6337        let actions_menu =
 6338            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6339                menu
 6340            } else {
 6341                return None;
 6342            };
 6343
 6344        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6345        let action = actions_menu.actions.get(action_ix)?;
 6346        let title = action.label();
 6347        let buffer = actions_menu.buffer;
 6348        let workspace = self.workspace()?;
 6349
 6350        match action {
 6351            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6352                workspace.update(cx, |workspace, cx| {
 6353                    workspace.schedule_resolved_task(
 6354                        task_source_kind,
 6355                        resolved_task,
 6356                        false,
 6357                        window,
 6358                        cx,
 6359                    );
 6360
 6361                    Some(Task::ready(Ok(())))
 6362                })
 6363            }
 6364            CodeActionsItem::CodeAction {
 6365                excerpt_id,
 6366                action,
 6367                provider,
 6368            } => {
 6369                let apply_code_action =
 6370                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6371                let workspace = workspace.downgrade();
 6372                Some(cx.spawn_in(window, async move |editor, cx| {
 6373                    let project_transaction = apply_code_action.await?;
 6374                    Self::open_project_transaction(
 6375                        &editor,
 6376                        workspace,
 6377                        project_transaction,
 6378                        title,
 6379                        cx,
 6380                    )
 6381                    .await
 6382                }))
 6383            }
 6384            CodeActionsItem::DebugScenario(scenario) => {
 6385                let context = actions_menu.actions.context;
 6386
 6387                workspace.update(cx, |workspace, cx| {
 6388                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6389                    workspace.start_debug_session(
 6390                        scenario,
 6391                        context,
 6392                        Some(buffer),
 6393                        None,
 6394                        window,
 6395                        cx,
 6396                    );
 6397                });
 6398                Some(Task::ready(Ok(())))
 6399            }
 6400        }
 6401    }
 6402
 6403    pub async fn open_project_transaction(
 6404        editor: &WeakEntity<Editor>,
 6405        workspace: WeakEntity<Workspace>,
 6406        transaction: ProjectTransaction,
 6407        title: String,
 6408        cx: &mut AsyncWindowContext,
 6409    ) -> Result<()> {
 6410        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6411        cx.update(|_, cx| {
 6412            entries.sort_unstable_by_key(|(buffer, _)| {
 6413                buffer.read(cx).file().map(|f| f.path().clone())
 6414            });
 6415        })?;
 6416
 6417        // If the project transaction's edits are all contained within this editor, then
 6418        // avoid opening a new editor to display them.
 6419
 6420        if let Some((buffer, transaction)) = entries.first() {
 6421            if entries.len() == 1 {
 6422                let excerpt = editor.update(cx, |editor, cx| {
 6423                    editor
 6424                        .buffer()
 6425                        .read(cx)
 6426                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6427                })?;
 6428                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6429                    && excerpted_buffer == *buffer
 6430                {
 6431                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6432                        let excerpt_range = excerpt_range.to_offset(buffer);
 6433                        buffer
 6434                            .edited_ranges_for_transaction::<usize>(transaction)
 6435                            .all(|range| {
 6436                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6437                            })
 6438                    })?;
 6439
 6440                    if all_edits_within_excerpt {
 6441                        return Ok(());
 6442                    }
 6443                }
 6444            }
 6445        } else {
 6446            return Ok(());
 6447        }
 6448
 6449        let mut ranges_to_highlight = Vec::new();
 6450        let excerpt_buffer = cx.new(|cx| {
 6451            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6452            for (buffer_handle, transaction) in &entries {
 6453                let edited_ranges = buffer_handle
 6454                    .read(cx)
 6455                    .edited_ranges_for_transaction::<Point>(transaction)
 6456                    .collect::<Vec<_>>();
 6457                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6458                    PathKey::for_buffer(buffer_handle, cx),
 6459                    buffer_handle.clone(),
 6460                    edited_ranges,
 6461                    multibuffer_context_lines(cx),
 6462                    cx,
 6463                );
 6464
 6465                ranges_to_highlight.extend(ranges);
 6466            }
 6467            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6468            multibuffer
 6469        })?;
 6470
 6471        workspace.update_in(cx, |workspace, window, cx| {
 6472            let project = workspace.project().clone();
 6473            let editor =
 6474                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6475            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6476            editor.update(cx, |editor, cx| {
 6477                editor.highlight_background::<Self>(
 6478                    &ranges_to_highlight,
 6479                    |theme| theme.colors().editor_highlighted_line_background,
 6480                    cx,
 6481                );
 6482            });
 6483        })?;
 6484
 6485        Ok(())
 6486    }
 6487
 6488    pub fn clear_code_action_providers(&mut self) {
 6489        self.code_action_providers.clear();
 6490        self.available_code_actions.take();
 6491    }
 6492
 6493    pub fn add_code_action_provider(
 6494        &mut self,
 6495        provider: Rc<dyn CodeActionProvider>,
 6496        window: &mut Window,
 6497        cx: &mut Context<Self>,
 6498    ) {
 6499        if self
 6500            .code_action_providers
 6501            .iter()
 6502            .any(|existing_provider| existing_provider.id() == provider.id())
 6503        {
 6504            return;
 6505        }
 6506
 6507        self.code_action_providers.push(provider);
 6508        self.refresh_code_actions(window, cx);
 6509    }
 6510
 6511    pub fn remove_code_action_provider(
 6512        &mut self,
 6513        id: Arc<str>,
 6514        window: &mut Window,
 6515        cx: &mut Context<Self>,
 6516    ) {
 6517        self.code_action_providers
 6518            .retain(|provider| provider.id() != id);
 6519        self.refresh_code_actions(window, cx);
 6520    }
 6521
 6522    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6523        !self.code_action_providers.is_empty()
 6524            && EditorSettings::get_global(cx).toolbar.code_actions
 6525    }
 6526
 6527    pub fn has_available_code_actions(&self) -> bool {
 6528        self.available_code_actions
 6529            .as_ref()
 6530            .is_some_and(|(_, actions)| !actions.is_empty())
 6531    }
 6532
 6533    fn render_inline_code_actions(
 6534        &self,
 6535        icon_size: ui::IconSize,
 6536        display_row: DisplayRow,
 6537        is_active: bool,
 6538        cx: &mut Context<Self>,
 6539    ) -> AnyElement {
 6540        let show_tooltip = !self.context_menu_visible();
 6541        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6542            .icon_size(icon_size)
 6543            .shape(ui::IconButtonShape::Square)
 6544            .icon_color(ui::Color::Hidden)
 6545            .toggle_state(is_active)
 6546            .when(show_tooltip, |this| {
 6547                this.tooltip({
 6548                    let focus_handle = self.focus_handle.clone();
 6549                    move |window, cx| {
 6550                        Tooltip::for_action_in(
 6551                            "Toggle Code Actions",
 6552                            &ToggleCodeActions {
 6553                                deployed_from: None,
 6554                                quick_launch: false,
 6555                            },
 6556                            &focus_handle,
 6557                            window,
 6558                            cx,
 6559                        )
 6560                    }
 6561                })
 6562            })
 6563            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6564                window.focus(&editor.focus_handle(cx));
 6565                editor.toggle_code_actions(
 6566                    &crate::actions::ToggleCodeActions {
 6567                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6568                            display_row,
 6569                        )),
 6570                        quick_launch: false,
 6571                    },
 6572                    window,
 6573                    cx,
 6574                );
 6575            }))
 6576            .into_any_element()
 6577    }
 6578
 6579    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6580        &self.context_menu
 6581    }
 6582
 6583    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6584        let newest_selection = self.selections.newest_anchor().clone();
 6585        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6586        let buffer = self.buffer.read(cx);
 6587        if newest_selection.head().diff_base_anchor.is_some() {
 6588            return None;
 6589        }
 6590        let (start_buffer, start) =
 6591            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6592        let (end_buffer, end) =
 6593            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6594        if start_buffer != end_buffer {
 6595            return None;
 6596        }
 6597
 6598        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6599            cx.background_executor()
 6600                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6601                .await;
 6602
 6603            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6604                let providers = this.code_action_providers.clone();
 6605                let tasks = this
 6606                    .code_action_providers
 6607                    .iter()
 6608                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6609                    .collect::<Vec<_>>();
 6610                (providers, tasks)
 6611            })?;
 6612
 6613            let mut actions = Vec::new();
 6614            for (provider, provider_actions) in
 6615                providers.into_iter().zip(future::join_all(tasks).await)
 6616            {
 6617                if let Some(provider_actions) = provider_actions.log_err() {
 6618                    actions.extend(provider_actions.into_iter().map(|action| {
 6619                        AvailableCodeAction {
 6620                            excerpt_id: newest_selection.start.excerpt_id,
 6621                            action,
 6622                            provider: provider.clone(),
 6623                        }
 6624                    }));
 6625                }
 6626            }
 6627
 6628            this.update(cx, |this, cx| {
 6629                this.available_code_actions = if actions.is_empty() {
 6630                    None
 6631                } else {
 6632                    Some((
 6633                        Location {
 6634                            buffer: start_buffer,
 6635                            range: start..end,
 6636                        },
 6637                        actions.into(),
 6638                    ))
 6639                };
 6640                cx.notify();
 6641            })
 6642        }));
 6643        None
 6644    }
 6645
 6646    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6647        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6648            self.show_git_blame_inline = false;
 6649
 6650            self.show_git_blame_inline_delay_task =
 6651                Some(cx.spawn_in(window, async move |this, cx| {
 6652                    cx.background_executor().timer(delay).await;
 6653
 6654                    this.update(cx, |this, cx| {
 6655                        this.show_git_blame_inline = true;
 6656                        cx.notify();
 6657                    })
 6658                    .log_err();
 6659                }));
 6660        }
 6661    }
 6662
 6663    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6664        let snapshot = self.snapshot(window, cx);
 6665        let cursor = self.selections.newest::<Point>(cx).head();
 6666        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6667        else {
 6668            return;
 6669        };
 6670
 6671        let Some(blame) = self.blame.as_ref() else {
 6672            return;
 6673        };
 6674
 6675        let row_info = RowInfo {
 6676            buffer_id: Some(buffer.remote_id()),
 6677            buffer_row: Some(point.row),
 6678            ..Default::default()
 6679        };
 6680        let Some((buffer, blame_entry)) = blame
 6681            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6682            .flatten()
 6683        else {
 6684            return;
 6685        };
 6686
 6687        let anchor = self.selections.newest_anchor().head();
 6688        let position = self.to_pixel_point(anchor, &snapshot, window);
 6689        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6690            self.show_blame_popover(
 6691                buffer,
 6692                &blame_entry,
 6693                position + last_bounds.origin,
 6694                true,
 6695                cx,
 6696            );
 6697        };
 6698    }
 6699
 6700    fn show_blame_popover(
 6701        &mut self,
 6702        buffer: BufferId,
 6703        blame_entry: &BlameEntry,
 6704        position: gpui::Point<Pixels>,
 6705        ignore_timeout: bool,
 6706        cx: &mut Context<Self>,
 6707    ) {
 6708        if let Some(state) = &mut self.inline_blame_popover {
 6709            state.hide_task.take();
 6710        } else {
 6711            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6712            let blame_entry = blame_entry.clone();
 6713            let show_task = cx.spawn(async move |editor, cx| {
 6714                if !ignore_timeout {
 6715                    cx.background_executor()
 6716                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6717                        .await;
 6718                }
 6719                editor
 6720                    .update(cx, |editor, cx| {
 6721                        editor.inline_blame_popover_show_task.take();
 6722                        let Some(blame) = editor.blame.as_ref() else {
 6723                            return;
 6724                        };
 6725                        let blame = blame.read(cx);
 6726                        let details = blame.details_for_entry(buffer, &blame_entry);
 6727                        let markdown = cx.new(|cx| {
 6728                            Markdown::new(
 6729                                details
 6730                                    .as_ref()
 6731                                    .map(|message| message.message.clone())
 6732                                    .unwrap_or_default(),
 6733                                None,
 6734                                None,
 6735                                cx,
 6736                            )
 6737                        });
 6738                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6739                            position,
 6740                            hide_task: None,
 6741                            popover_bounds: None,
 6742                            popover_state: InlineBlamePopoverState {
 6743                                scroll_handle: ScrollHandle::new(),
 6744                                commit_message: details,
 6745                                markdown,
 6746                            },
 6747                            keyboard_grace: ignore_timeout,
 6748                        });
 6749                        cx.notify();
 6750                    })
 6751                    .ok();
 6752            });
 6753            self.inline_blame_popover_show_task = Some(show_task);
 6754        }
 6755    }
 6756
 6757    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6758        self.inline_blame_popover_show_task.take();
 6759        if let Some(state) = &mut self.inline_blame_popover {
 6760            let hide_task = cx.spawn(async move |editor, cx| {
 6761                cx.background_executor()
 6762                    .timer(std::time::Duration::from_millis(100))
 6763                    .await;
 6764                editor
 6765                    .update(cx, |editor, cx| {
 6766                        editor.inline_blame_popover.take();
 6767                        cx.notify();
 6768                    })
 6769                    .ok();
 6770            });
 6771            state.hide_task = Some(hide_task);
 6772        }
 6773    }
 6774
 6775    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6776        if self.pending_rename.is_some() {
 6777            return None;
 6778        }
 6779
 6780        let provider = self.semantics_provider.clone()?;
 6781        let buffer = self.buffer.read(cx);
 6782        let newest_selection = self.selections.newest_anchor().clone();
 6783        let cursor_position = newest_selection.head();
 6784        let (cursor_buffer, cursor_buffer_position) =
 6785            buffer.text_anchor_for_position(cursor_position, cx)?;
 6786        let (tail_buffer, tail_buffer_position) =
 6787            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6788        if cursor_buffer != tail_buffer {
 6789            return None;
 6790        }
 6791
 6792        let snapshot = cursor_buffer.read(cx).snapshot();
 6793        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6794        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6795        if start_word_range != end_word_range {
 6796            self.document_highlights_task.take();
 6797            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6798            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6799            return None;
 6800        }
 6801
 6802        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6803        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6804            cx.background_executor()
 6805                .timer(Duration::from_millis(debounce))
 6806                .await;
 6807
 6808            let highlights = if let Some(highlights) = cx
 6809                .update(|cx| {
 6810                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6811                })
 6812                .ok()
 6813                .flatten()
 6814            {
 6815                highlights.await.log_err()
 6816            } else {
 6817                None
 6818            };
 6819
 6820            if let Some(highlights) = highlights {
 6821                this.update(cx, |this, cx| {
 6822                    if this.pending_rename.is_some() {
 6823                        return;
 6824                    }
 6825
 6826                    let buffer = this.buffer.read(cx);
 6827                    if buffer
 6828                        .text_anchor_for_position(cursor_position, cx)
 6829                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6830                    {
 6831                        return;
 6832                    }
 6833
 6834                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6835                    let mut write_ranges = Vec::new();
 6836                    let mut read_ranges = Vec::new();
 6837                    for highlight in highlights {
 6838                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6839                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6840                        {
 6841                            let start = highlight
 6842                                .range
 6843                                .start
 6844                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6845                            let end = highlight
 6846                                .range
 6847                                .end
 6848                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6849                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6850                                continue;
 6851                            }
 6852
 6853                            let range = Anchor {
 6854                                buffer_id: Some(buffer_id),
 6855                                excerpt_id,
 6856                                text_anchor: start,
 6857                                diff_base_anchor: None,
 6858                            }..Anchor {
 6859                                buffer_id: Some(buffer_id),
 6860                                excerpt_id,
 6861                                text_anchor: end,
 6862                                diff_base_anchor: None,
 6863                            };
 6864                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6865                                write_ranges.push(range);
 6866                            } else {
 6867                                read_ranges.push(range);
 6868                            }
 6869                        }
 6870                    }
 6871
 6872                    this.highlight_background::<DocumentHighlightRead>(
 6873                        &read_ranges,
 6874                        |theme| theme.colors().editor_document_highlight_read_background,
 6875                        cx,
 6876                    );
 6877                    this.highlight_background::<DocumentHighlightWrite>(
 6878                        &write_ranges,
 6879                        |theme| theme.colors().editor_document_highlight_write_background,
 6880                        cx,
 6881                    );
 6882                    cx.notify();
 6883                })
 6884                .log_err();
 6885            }
 6886        }));
 6887        None
 6888    }
 6889
 6890    fn prepare_highlight_query_from_selection(
 6891        &mut self,
 6892        cx: &mut Context<Editor>,
 6893    ) -> Option<(String, Range<Anchor>)> {
 6894        if matches!(self.mode, EditorMode::SingleLine) {
 6895            return None;
 6896        }
 6897        if !EditorSettings::get_global(cx).selection_highlight {
 6898            return None;
 6899        }
 6900        if self.selections.count() != 1 || self.selections.line_mode {
 6901            return None;
 6902        }
 6903        let selection = self.selections.newest::<Point>(cx);
 6904        if selection.is_empty() || selection.start.row != selection.end.row {
 6905            return None;
 6906        }
 6907        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6908        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6909        let query = multi_buffer_snapshot
 6910            .text_for_range(selection_anchor_range.clone())
 6911            .collect::<String>();
 6912        if query.trim().is_empty() {
 6913            return None;
 6914        }
 6915        Some((query, selection_anchor_range))
 6916    }
 6917
 6918    fn update_selection_occurrence_highlights(
 6919        &mut self,
 6920        query_text: String,
 6921        query_range: Range<Anchor>,
 6922        multi_buffer_range_to_query: Range<Point>,
 6923        use_debounce: bool,
 6924        window: &mut Window,
 6925        cx: &mut Context<Editor>,
 6926    ) -> Task<()> {
 6927        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6928        cx.spawn_in(window, async move |editor, cx| {
 6929            if use_debounce {
 6930                cx.background_executor()
 6931                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6932                    .await;
 6933            }
 6934            let match_task = cx.background_spawn(async move {
 6935                let buffer_ranges = multi_buffer_snapshot
 6936                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6937                    .into_iter()
 6938                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6939                let mut match_ranges = Vec::new();
 6940                let Ok(regex) = project::search::SearchQuery::text(
 6941                    query_text.clone(),
 6942                    false,
 6943                    false,
 6944                    false,
 6945                    Default::default(),
 6946                    Default::default(),
 6947                    false,
 6948                    None,
 6949                ) else {
 6950                    return Vec::default();
 6951                };
 6952                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6953                    match_ranges.extend(
 6954                        regex
 6955                            .search(buffer_snapshot, Some(search_range.clone()))
 6956                            .await
 6957                            .into_iter()
 6958                            .filter_map(|match_range| {
 6959                                let match_start = buffer_snapshot
 6960                                    .anchor_after(search_range.start + match_range.start);
 6961                                let match_end = buffer_snapshot
 6962                                    .anchor_before(search_range.start + match_range.end);
 6963                                let match_anchor_range = Anchor::range_in_buffer(
 6964                                    excerpt_id,
 6965                                    buffer_snapshot.remote_id(),
 6966                                    match_start..match_end,
 6967                                );
 6968                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6969                            }),
 6970                    );
 6971                }
 6972                match_ranges
 6973            });
 6974            let match_ranges = match_task.await;
 6975            editor
 6976                .update_in(cx, |editor, _, cx| {
 6977                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6978                    if !match_ranges.is_empty() {
 6979                        editor.highlight_background::<SelectedTextHighlight>(
 6980                            &match_ranges,
 6981                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6982                            cx,
 6983                        )
 6984                    }
 6985                })
 6986                .log_err();
 6987        })
 6988    }
 6989
 6990    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6991        struct NewlineFold;
 6992        let type_id = std::any::TypeId::of::<NewlineFold>();
 6993        if !self.mode.is_single_line() {
 6994            return;
 6995        }
 6996        let snapshot = self.snapshot(window, cx);
 6997        if snapshot.buffer_snapshot.max_point().row == 0 {
 6998            return;
 6999        }
 7000        let task = cx.background_spawn(async move {
 7001            let new_newlines = snapshot
 7002                .buffer_chars_at(0)
 7003                .filter_map(|(c, i)| {
 7004                    if c == '\n' {
 7005                        Some(
 7006                            snapshot.buffer_snapshot.anchor_after(i)
 7007                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7008                        )
 7009                    } else {
 7010                        None
 7011                    }
 7012                })
 7013                .collect::<Vec<_>>();
 7014            let existing_newlines = snapshot
 7015                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7016                .filter_map(|fold| {
 7017                    if fold.placeholder.type_tag == Some(type_id) {
 7018                        Some(fold.range.start..fold.range.end)
 7019                    } else {
 7020                        None
 7021                    }
 7022                })
 7023                .collect::<Vec<_>>();
 7024
 7025            (new_newlines, existing_newlines)
 7026        });
 7027        self.folding_newlines = cx.spawn(async move |this, cx| {
 7028            let (new_newlines, existing_newlines) = task.await;
 7029            if new_newlines == existing_newlines {
 7030                return;
 7031            }
 7032            let placeholder = FoldPlaceholder {
 7033                render: Arc::new(move |_, _, cx| {
 7034                    div()
 7035                        .bg(cx.theme().status().hint_background)
 7036                        .border_b_1()
 7037                        .size_full()
 7038                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7039                        .border_color(cx.theme().status().hint)
 7040                        .child("\\n")
 7041                        .into_any()
 7042                }),
 7043                constrain_width: false,
 7044                merge_adjacent: false,
 7045                type_tag: Some(type_id),
 7046            };
 7047            let creases = new_newlines
 7048                .into_iter()
 7049                .map(|range| Crease::simple(range, placeholder.clone()))
 7050                .collect();
 7051            this.update(cx, |this, cx| {
 7052                this.display_map.update(cx, |display_map, cx| {
 7053                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7054                    display_map.fold(creases, cx);
 7055                });
 7056            })
 7057            .ok();
 7058        });
 7059    }
 7060
 7061    fn refresh_selected_text_highlights(
 7062        &mut self,
 7063        on_buffer_edit: bool,
 7064        window: &mut Window,
 7065        cx: &mut Context<Editor>,
 7066    ) {
 7067        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7068        else {
 7069            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7070            self.quick_selection_highlight_task.take();
 7071            self.debounced_selection_highlight_task.take();
 7072            return;
 7073        };
 7074        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7075        if on_buffer_edit
 7076            || self
 7077                .quick_selection_highlight_task
 7078                .as_ref()
 7079                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7080        {
 7081            let multi_buffer_visible_start = self
 7082                .scroll_manager
 7083                .anchor()
 7084                .anchor
 7085                .to_point(&multi_buffer_snapshot);
 7086            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7087                multi_buffer_visible_start
 7088                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7089                Bias::Left,
 7090            );
 7091            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7092            self.quick_selection_highlight_task = Some((
 7093                query_range.clone(),
 7094                self.update_selection_occurrence_highlights(
 7095                    query_text.clone(),
 7096                    query_range.clone(),
 7097                    multi_buffer_visible_range,
 7098                    false,
 7099                    window,
 7100                    cx,
 7101                ),
 7102            ));
 7103        }
 7104        if on_buffer_edit
 7105            || self
 7106                .debounced_selection_highlight_task
 7107                .as_ref()
 7108                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7109        {
 7110            let multi_buffer_start = multi_buffer_snapshot
 7111                .anchor_before(0)
 7112                .to_point(&multi_buffer_snapshot);
 7113            let multi_buffer_end = multi_buffer_snapshot
 7114                .anchor_after(multi_buffer_snapshot.len())
 7115                .to_point(&multi_buffer_snapshot);
 7116            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7117            self.debounced_selection_highlight_task = Some((
 7118                query_range.clone(),
 7119                self.update_selection_occurrence_highlights(
 7120                    query_text,
 7121                    query_range,
 7122                    multi_buffer_full_range,
 7123                    true,
 7124                    window,
 7125                    cx,
 7126                ),
 7127            ));
 7128        }
 7129    }
 7130
 7131    pub fn refresh_edit_prediction(
 7132        &mut self,
 7133        debounce: bool,
 7134        user_requested: bool,
 7135        window: &mut Window,
 7136        cx: &mut Context<Self>,
 7137    ) -> Option<()> {
 7138        if DisableAiSettings::get_global(cx).disable_ai {
 7139            return None;
 7140        }
 7141
 7142        let provider = self.edit_prediction_provider()?;
 7143        let cursor = self.selections.newest_anchor().head();
 7144        let (buffer, cursor_buffer_position) =
 7145            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7146
 7147        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7148            self.discard_edit_prediction(false, cx);
 7149            return None;
 7150        }
 7151
 7152        if !user_requested
 7153            && (!self.should_show_edit_predictions()
 7154                || !self.is_focused(window)
 7155                || buffer.read(cx).is_empty())
 7156        {
 7157            self.discard_edit_prediction(false, cx);
 7158            return None;
 7159        }
 7160
 7161        self.update_visible_edit_prediction(window, cx);
 7162        provider.refresh(
 7163            self.project.clone(),
 7164            buffer,
 7165            cursor_buffer_position,
 7166            debounce,
 7167            cx,
 7168        );
 7169        Some(())
 7170    }
 7171
 7172    fn show_edit_predictions_in_menu(&self) -> bool {
 7173        match self.edit_prediction_settings {
 7174            EditPredictionSettings::Disabled => false,
 7175            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7176        }
 7177    }
 7178
 7179    pub fn edit_predictions_enabled(&self) -> bool {
 7180        match self.edit_prediction_settings {
 7181            EditPredictionSettings::Disabled => false,
 7182            EditPredictionSettings::Enabled { .. } => true,
 7183        }
 7184    }
 7185
 7186    fn edit_prediction_requires_modifier(&self) -> bool {
 7187        match self.edit_prediction_settings {
 7188            EditPredictionSettings::Disabled => false,
 7189            EditPredictionSettings::Enabled {
 7190                preview_requires_modifier,
 7191                ..
 7192            } => preview_requires_modifier,
 7193        }
 7194    }
 7195
 7196    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7197        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7198            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7199            self.discard_edit_prediction(false, cx);
 7200        } else {
 7201            let selection = self.selections.newest_anchor();
 7202            let cursor = selection.head();
 7203
 7204            if let Some((buffer, cursor_buffer_position)) =
 7205                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7206            {
 7207                self.edit_prediction_settings =
 7208                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7209            }
 7210        }
 7211    }
 7212
 7213    fn edit_prediction_settings_at_position(
 7214        &self,
 7215        buffer: &Entity<Buffer>,
 7216        buffer_position: language::Anchor,
 7217        cx: &App,
 7218    ) -> EditPredictionSettings {
 7219        if !self.mode.is_full()
 7220            || !self.show_edit_predictions_override.unwrap_or(true)
 7221            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7222        {
 7223            return EditPredictionSettings::Disabled;
 7224        }
 7225
 7226        let buffer = buffer.read(cx);
 7227
 7228        let file = buffer.file();
 7229
 7230        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7231            return EditPredictionSettings::Disabled;
 7232        };
 7233
 7234        let by_provider = matches!(
 7235            self.menu_edit_predictions_policy,
 7236            MenuEditPredictionsPolicy::ByProvider
 7237        );
 7238
 7239        let show_in_menu = by_provider
 7240            && self
 7241                .edit_prediction_provider
 7242                .as_ref()
 7243                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7244
 7245        let preview_requires_modifier =
 7246            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7247
 7248        EditPredictionSettings::Enabled {
 7249            show_in_menu,
 7250            preview_requires_modifier,
 7251        }
 7252    }
 7253
 7254    fn should_show_edit_predictions(&self) -> bool {
 7255        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7256    }
 7257
 7258    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7259        matches!(
 7260            self.edit_prediction_preview,
 7261            EditPredictionPreview::Active { .. }
 7262        )
 7263    }
 7264
 7265    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7266        let cursor = self.selections.newest_anchor().head();
 7267        if let Some((buffer, cursor_position)) =
 7268            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7269        {
 7270            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7271        } else {
 7272            false
 7273        }
 7274    }
 7275
 7276    pub fn supports_minimap(&self, cx: &App) -> bool {
 7277        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7278    }
 7279
 7280    fn edit_predictions_enabled_in_buffer(
 7281        &self,
 7282        buffer: &Entity<Buffer>,
 7283        buffer_position: language::Anchor,
 7284        cx: &App,
 7285    ) -> bool {
 7286        maybe!({
 7287            if self.read_only(cx) {
 7288                return Some(false);
 7289            }
 7290            let provider = self.edit_prediction_provider()?;
 7291            if !provider.is_enabled(buffer, buffer_position, cx) {
 7292                return Some(false);
 7293            }
 7294            let buffer = buffer.read(cx);
 7295            let Some(file) = buffer.file() else {
 7296                return Some(true);
 7297            };
 7298            let settings = all_language_settings(Some(file), cx);
 7299            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7300        })
 7301        .unwrap_or(false)
 7302    }
 7303
 7304    fn cycle_edit_prediction(
 7305        &mut self,
 7306        direction: Direction,
 7307        window: &mut Window,
 7308        cx: &mut Context<Self>,
 7309    ) -> Option<()> {
 7310        let provider = self.edit_prediction_provider()?;
 7311        let cursor = self.selections.newest_anchor().head();
 7312        let (buffer, cursor_buffer_position) =
 7313            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7314        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7315            return None;
 7316        }
 7317
 7318        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7319        self.update_visible_edit_prediction(window, cx);
 7320
 7321        Some(())
 7322    }
 7323
 7324    pub fn show_edit_prediction(
 7325        &mut self,
 7326        _: &ShowEditPrediction,
 7327        window: &mut Window,
 7328        cx: &mut Context<Self>,
 7329    ) {
 7330        if !self.has_active_edit_prediction() {
 7331            self.refresh_edit_prediction(false, true, window, cx);
 7332            return;
 7333        }
 7334
 7335        self.update_visible_edit_prediction(window, cx);
 7336    }
 7337
 7338    pub fn display_cursor_names(
 7339        &mut self,
 7340        _: &DisplayCursorNames,
 7341        window: &mut Window,
 7342        cx: &mut Context<Self>,
 7343    ) {
 7344        self.show_cursor_names(window, cx);
 7345    }
 7346
 7347    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7348        self.show_cursor_names = true;
 7349        cx.notify();
 7350        cx.spawn_in(window, async move |this, cx| {
 7351            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7352            this.update(cx, |this, cx| {
 7353                this.show_cursor_names = false;
 7354                cx.notify()
 7355            })
 7356            .ok()
 7357        })
 7358        .detach();
 7359    }
 7360
 7361    pub fn next_edit_prediction(
 7362        &mut self,
 7363        _: &NextEditPrediction,
 7364        window: &mut Window,
 7365        cx: &mut Context<Self>,
 7366    ) {
 7367        if self.has_active_edit_prediction() {
 7368            self.cycle_edit_prediction(Direction::Next, window, cx);
 7369        } else {
 7370            let is_copilot_disabled = self
 7371                .refresh_edit_prediction(false, true, window, cx)
 7372                .is_none();
 7373            if is_copilot_disabled {
 7374                cx.propagate();
 7375            }
 7376        }
 7377    }
 7378
 7379    pub fn previous_edit_prediction(
 7380        &mut self,
 7381        _: &PreviousEditPrediction,
 7382        window: &mut Window,
 7383        cx: &mut Context<Self>,
 7384    ) {
 7385        if self.has_active_edit_prediction() {
 7386            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7387        } else {
 7388            let is_copilot_disabled = self
 7389                .refresh_edit_prediction(false, true, window, cx)
 7390                .is_none();
 7391            if is_copilot_disabled {
 7392                cx.propagate();
 7393            }
 7394        }
 7395    }
 7396
 7397    pub fn accept_edit_prediction(
 7398        &mut self,
 7399        _: &AcceptEditPrediction,
 7400        window: &mut Window,
 7401        cx: &mut Context<Self>,
 7402    ) {
 7403        if self.show_edit_predictions_in_menu() {
 7404            self.hide_context_menu(window, cx);
 7405        }
 7406
 7407        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7408            return;
 7409        };
 7410
 7411        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7412
 7413        match &active_edit_prediction.completion {
 7414            EditPrediction::Move { target, .. } => {
 7415                let target = *target;
 7416
 7417                if let Some(position_map) = &self.last_position_map {
 7418                    if position_map
 7419                        .visible_row_range
 7420                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7421                        || !self.edit_prediction_requires_modifier()
 7422                    {
 7423                        self.unfold_ranges(&[target..target], true, false, cx);
 7424                        // Note that this is also done in vim's handler of the Tab action.
 7425                        self.change_selections(
 7426                            SelectionEffects::scroll(Autoscroll::newest()),
 7427                            window,
 7428                            cx,
 7429                            |selections| {
 7430                                selections.select_anchor_ranges([target..target]);
 7431                            },
 7432                        );
 7433                        self.clear_row_highlights::<EditPredictionPreview>();
 7434
 7435                        self.edit_prediction_preview
 7436                            .set_previous_scroll_position(None);
 7437                    } else {
 7438                        self.edit_prediction_preview
 7439                            .set_previous_scroll_position(Some(
 7440                                position_map.snapshot.scroll_anchor,
 7441                            ));
 7442
 7443                        self.highlight_rows::<EditPredictionPreview>(
 7444                            target..target,
 7445                            cx.theme().colors().editor_highlighted_line_background,
 7446                            RowHighlightOptions {
 7447                                autoscroll: true,
 7448                                ..Default::default()
 7449                            },
 7450                            cx,
 7451                        );
 7452                        self.request_autoscroll(Autoscroll::fit(), cx);
 7453                    }
 7454                }
 7455            }
 7456            EditPrediction::Edit { edits, .. } => {
 7457                if let Some(provider) = self.edit_prediction_provider() {
 7458                    provider.accept(cx);
 7459                }
 7460
 7461                // Store the transaction ID and selections before applying the edit
 7462                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7463
 7464                let snapshot = self.buffer.read(cx).snapshot(cx);
 7465                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7466
 7467                self.buffer.update(cx, |buffer, cx| {
 7468                    buffer.edit(edits.iter().cloned(), None, cx)
 7469                });
 7470
 7471                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7472                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7473                });
 7474
 7475                let selections = self.selections.disjoint_anchors();
 7476                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7477                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7478                    if has_new_transaction {
 7479                        self.selection_history
 7480                            .insert_transaction(transaction_id_now, selections);
 7481                    }
 7482                }
 7483
 7484                self.update_visible_edit_prediction(window, cx);
 7485                if self.active_edit_prediction.is_none() {
 7486                    self.refresh_edit_prediction(true, true, window, cx);
 7487                }
 7488
 7489                cx.notify();
 7490            }
 7491        }
 7492
 7493        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7494    }
 7495
 7496    pub fn accept_partial_edit_prediction(
 7497        &mut self,
 7498        _: &AcceptPartialEditPrediction,
 7499        window: &mut Window,
 7500        cx: &mut Context<Self>,
 7501    ) {
 7502        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7503            return;
 7504        };
 7505        if self.selections.count() != 1 {
 7506            return;
 7507        }
 7508
 7509        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7510
 7511        match &active_edit_prediction.completion {
 7512            EditPrediction::Move { target, .. } => {
 7513                let target = *target;
 7514                self.change_selections(
 7515                    SelectionEffects::scroll(Autoscroll::newest()),
 7516                    window,
 7517                    cx,
 7518                    |selections| {
 7519                        selections.select_anchor_ranges([target..target]);
 7520                    },
 7521                );
 7522            }
 7523            EditPrediction::Edit { edits, .. } => {
 7524                // Find an insertion that starts at the cursor position.
 7525                let snapshot = self.buffer.read(cx).snapshot(cx);
 7526                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7527                let insertion = edits.iter().find_map(|(range, text)| {
 7528                    let range = range.to_offset(&snapshot);
 7529                    if range.is_empty() && range.start == cursor_offset {
 7530                        Some(text)
 7531                    } else {
 7532                        None
 7533                    }
 7534                });
 7535
 7536                if let Some(text) = insertion {
 7537                    let mut partial_completion = text
 7538                        .chars()
 7539                        .by_ref()
 7540                        .take_while(|c| c.is_alphabetic())
 7541                        .collect::<String>();
 7542                    if partial_completion.is_empty() {
 7543                        partial_completion = text
 7544                            .chars()
 7545                            .by_ref()
 7546                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7547                            .collect::<String>();
 7548                    }
 7549
 7550                    cx.emit(EditorEvent::InputHandled {
 7551                        utf16_range_to_replace: None,
 7552                        text: partial_completion.clone().into(),
 7553                    });
 7554
 7555                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7556
 7557                    self.refresh_edit_prediction(true, true, window, cx);
 7558                    cx.notify();
 7559                } else {
 7560                    self.accept_edit_prediction(&Default::default(), window, cx);
 7561                }
 7562            }
 7563        }
 7564    }
 7565
 7566    fn discard_edit_prediction(
 7567        &mut self,
 7568        should_report_edit_prediction_event: bool,
 7569        cx: &mut Context<Self>,
 7570    ) -> bool {
 7571        if should_report_edit_prediction_event {
 7572            let completion_id = self
 7573                .active_edit_prediction
 7574                .as_ref()
 7575                .and_then(|active_completion| active_completion.completion_id.clone());
 7576
 7577            self.report_edit_prediction_event(completion_id, false, cx);
 7578        }
 7579
 7580        if let Some(provider) = self.edit_prediction_provider() {
 7581            provider.discard(cx);
 7582        }
 7583
 7584        self.take_active_edit_prediction(cx)
 7585    }
 7586
 7587    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7588        let Some(provider) = self.edit_prediction_provider() else {
 7589            return;
 7590        };
 7591
 7592        let Some((_, buffer, _)) = self
 7593            .buffer
 7594            .read(cx)
 7595            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7596        else {
 7597            return;
 7598        };
 7599
 7600        let extension = buffer
 7601            .read(cx)
 7602            .file()
 7603            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7604
 7605        let event_type = match accepted {
 7606            true => "Edit Prediction Accepted",
 7607            false => "Edit Prediction Discarded",
 7608        };
 7609        telemetry::event!(
 7610            event_type,
 7611            provider = provider.name(),
 7612            prediction_id = id,
 7613            suggestion_accepted = accepted,
 7614            file_extension = extension,
 7615        );
 7616    }
 7617
 7618    pub fn has_active_edit_prediction(&self) -> bool {
 7619        self.active_edit_prediction.is_some()
 7620    }
 7621
 7622    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7623        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7624            return false;
 7625        };
 7626
 7627        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7628        self.clear_highlights::<EditPredictionHighlight>(cx);
 7629        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7630        true
 7631    }
 7632
 7633    /// Returns true when we're displaying the edit prediction popover below the cursor
 7634    /// like we are not previewing and the LSP autocomplete menu is visible
 7635    /// or we are in `when_holding_modifier` mode.
 7636    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7637        if self.edit_prediction_preview_is_active()
 7638            || !self.show_edit_predictions_in_menu()
 7639            || !self.edit_predictions_enabled()
 7640        {
 7641            return false;
 7642        }
 7643
 7644        if self.has_visible_completions_menu() {
 7645            return true;
 7646        }
 7647
 7648        has_completion && self.edit_prediction_requires_modifier()
 7649    }
 7650
 7651    fn handle_modifiers_changed(
 7652        &mut self,
 7653        modifiers: Modifiers,
 7654        position_map: &PositionMap,
 7655        window: &mut Window,
 7656        cx: &mut Context<Self>,
 7657    ) {
 7658        if self.show_edit_predictions_in_menu() {
 7659            self.update_edit_prediction_preview(&modifiers, window, cx);
 7660        }
 7661
 7662        self.update_selection_mode(&modifiers, position_map, window, cx);
 7663
 7664        let mouse_position = window.mouse_position();
 7665        if !position_map.text_hitbox.is_hovered(window) {
 7666            return;
 7667        }
 7668
 7669        self.update_hovered_link(
 7670            position_map.point_for_position(mouse_position),
 7671            &position_map.snapshot,
 7672            modifiers,
 7673            window,
 7674            cx,
 7675        )
 7676    }
 7677
 7678    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7679        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7680        if invert {
 7681            match multi_cursor_setting {
 7682                MultiCursorModifier::Alt => modifiers.alt,
 7683                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7684            }
 7685        } else {
 7686            match multi_cursor_setting {
 7687                MultiCursorModifier::Alt => modifiers.secondary(),
 7688                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7689            }
 7690        }
 7691    }
 7692
 7693    fn columnar_selection_mode(
 7694        modifiers: &Modifiers,
 7695        cx: &mut Context<Self>,
 7696    ) -> Option<ColumnarMode> {
 7697        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7698            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7699                Some(ColumnarMode::FromMouse)
 7700            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7701                Some(ColumnarMode::FromSelection)
 7702            } else {
 7703                None
 7704            }
 7705        } else {
 7706            None
 7707        }
 7708    }
 7709
 7710    fn update_selection_mode(
 7711        &mut self,
 7712        modifiers: &Modifiers,
 7713        position_map: &PositionMap,
 7714        window: &mut Window,
 7715        cx: &mut Context<Self>,
 7716    ) {
 7717        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7718            return;
 7719        };
 7720        if self.selections.pending.is_none() {
 7721            return;
 7722        }
 7723
 7724        let mouse_position = window.mouse_position();
 7725        let point_for_position = position_map.point_for_position(mouse_position);
 7726        let position = point_for_position.previous_valid;
 7727
 7728        self.select(
 7729            SelectPhase::BeginColumnar {
 7730                position,
 7731                reset: false,
 7732                mode,
 7733                goal_column: point_for_position.exact_unclipped.column(),
 7734            },
 7735            window,
 7736            cx,
 7737        );
 7738    }
 7739
 7740    fn update_edit_prediction_preview(
 7741        &mut self,
 7742        modifiers: &Modifiers,
 7743        window: &mut Window,
 7744        cx: &mut Context<Self>,
 7745    ) {
 7746        let mut modifiers_held = false;
 7747        if let Some(accept_keystroke) = self
 7748            .accept_edit_prediction_keybind(false, window, cx)
 7749            .keystroke()
 7750        {
 7751            modifiers_held = modifiers_held
 7752                || (accept_keystroke.modifiers() == modifiers
 7753                    && accept_keystroke.modifiers().modified());
 7754        };
 7755        if let Some(accept_partial_keystroke) = self
 7756            .accept_edit_prediction_keybind(true, window, cx)
 7757            .keystroke()
 7758        {
 7759            modifiers_held = modifiers_held
 7760                || (accept_partial_keystroke.modifiers() == modifiers
 7761                    && accept_partial_keystroke.modifiers().modified());
 7762        }
 7763
 7764        if modifiers_held {
 7765            if matches!(
 7766                self.edit_prediction_preview,
 7767                EditPredictionPreview::Inactive { .. }
 7768            ) {
 7769                self.edit_prediction_preview = EditPredictionPreview::Active {
 7770                    previous_scroll_position: None,
 7771                    since: Instant::now(),
 7772                };
 7773
 7774                self.update_visible_edit_prediction(window, cx);
 7775                cx.notify();
 7776            }
 7777        } else if let EditPredictionPreview::Active {
 7778            previous_scroll_position,
 7779            since,
 7780        } = self.edit_prediction_preview
 7781        {
 7782            if let (Some(previous_scroll_position), Some(position_map)) =
 7783                (previous_scroll_position, self.last_position_map.as_ref())
 7784            {
 7785                self.set_scroll_position(
 7786                    previous_scroll_position
 7787                        .scroll_position(&position_map.snapshot.display_snapshot),
 7788                    window,
 7789                    cx,
 7790                );
 7791            }
 7792
 7793            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7794                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7795            };
 7796            self.clear_row_highlights::<EditPredictionPreview>();
 7797            self.update_visible_edit_prediction(window, cx);
 7798            cx.notify();
 7799        }
 7800    }
 7801
 7802    fn update_visible_edit_prediction(
 7803        &mut self,
 7804        _window: &mut Window,
 7805        cx: &mut Context<Self>,
 7806    ) -> Option<()> {
 7807        if DisableAiSettings::get_global(cx).disable_ai {
 7808            return None;
 7809        }
 7810
 7811        if self.ime_transaction.is_some() {
 7812            self.discard_edit_prediction(false, cx);
 7813            return None;
 7814        }
 7815
 7816        let selection = self.selections.newest_anchor();
 7817        let cursor = selection.head();
 7818        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7819        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7820        let excerpt_id = cursor.excerpt_id;
 7821
 7822        let show_in_menu = self.show_edit_predictions_in_menu();
 7823        let completions_menu_has_precedence = !show_in_menu
 7824            && (self.context_menu.borrow().is_some()
 7825                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7826
 7827        if completions_menu_has_precedence
 7828            || !offset_selection.is_empty()
 7829            || self
 7830                .active_edit_prediction
 7831                .as_ref()
 7832                .is_some_and(|completion| {
 7833                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7834                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7835                    !invalidation_range.contains(&offset_selection.head())
 7836                })
 7837        {
 7838            self.discard_edit_prediction(false, cx);
 7839            return None;
 7840        }
 7841
 7842        self.take_active_edit_prediction(cx);
 7843        let Some(provider) = self.edit_prediction_provider() else {
 7844            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7845            return None;
 7846        };
 7847
 7848        let (buffer, cursor_buffer_position) =
 7849            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7850
 7851        self.edit_prediction_settings =
 7852            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7853
 7854        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7855            self.discard_edit_prediction(false, cx);
 7856            return None;
 7857        };
 7858
 7859        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7860
 7861        if self.edit_prediction_indent_conflict {
 7862            let cursor_point = cursor.to_point(&multibuffer);
 7863
 7864            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7865
 7866            if let Some((_, indent)) = indents.iter().next()
 7867                && indent.len == cursor_point.column
 7868            {
 7869                self.edit_prediction_indent_conflict = false;
 7870            }
 7871        }
 7872
 7873        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7874        let edits = edit_prediction
 7875            .edits
 7876            .into_iter()
 7877            .flat_map(|(range, new_text)| {
 7878                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7879                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7880                Some((start..end, new_text))
 7881            })
 7882            .collect::<Vec<_>>();
 7883        if edits.is_empty() {
 7884            return None;
 7885        }
 7886
 7887        let first_edit_start = edits.first().unwrap().0.start;
 7888        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7889        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7890
 7891        let last_edit_end = edits.last().unwrap().0.end;
 7892        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7893        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7894
 7895        let cursor_row = cursor.to_point(&multibuffer).row;
 7896
 7897        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7898
 7899        let mut inlay_ids = Vec::new();
 7900        let invalidation_row_range;
 7901        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7902            Some(cursor_row..edit_end_row)
 7903        } else if cursor_row > edit_end_row {
 7904            Some(edit_start_row..cursor_row)
 7905        } else {
 7906            None
 7907        };
 7908        let supports_jump = self
 7909            .edit_prediction_provider
 7910            .as_ref()
 7911            .map(|provider| provider.provider.supports_jump_to_edit())
 7912            .unwrap_or(true);
 7913
 7914        let is_move = supports_jump
 7915            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7916        let completion = if is_move {
 7917            invalidation_row_range =
 7918                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7919            let target = first_edit_start;
 7920            EditPrediction::Move { target, snapshot }
 7921        } else {
 7922            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7923                && !self.edit_predictions_hidden_for_vim_mode;
 7924
 7925            if show_completions_in_buffer {
 7926                if edits
 7927                    .iter()
 7928                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7929                {
 7930                    let mut inlays = Vec::new();
 7931                    for (range, new_text) in &edits {
 7932                        let inlay = Inlay::edit_prediction(
 7933                            post_inc(&mut self.next_inlay_id),
 7934                            range.start,
 7935                            new_text.as_str(),
 7936                        );
 7937                        inlay_ids.push(inlay.id);
 7938                        inlays.push(inlay);
 7939                    }
 7940
 7941                    self.splice_inlays(&[], inlays, cx);
 7942                } else {
 7943                    let background_color = cx.theme().status().deleted_background;
 7944                    self.highlight_text::<EditPredictionHighlight>(
 7945                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7946                        HighlightStyle {
 7947                            background_color: Some(background_color),
 7948                            ..Default::default()
 7949                        },
 7950                        cx,
 7951                    );
 7952                }
 7953            }
 7954
 7955            invalidation_row_range = edit_start_row..edit_end_row;
 7956
 7957            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7958                if provider.show_tab_accept_marker() {
 7959                    EditDisplayMode::TabAccept
 7960                } else {
 7961                    EditDisplayMode::Inline
 7962                }
 7963            } else {
 7964                EditDisplayMode::DiffPopover
 7965            };
 7966
 7967            EditPrediction::Edit {
 7968                edits,
 7969                edit_preview: edit_prediction.edit_preview,
 7970                display_mode,
 7971                snapshot,
 7972            }
 7973        };
 7974
 7975        let invalidation_range = multibuffer
 7976            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7977            ..multibuffer.anchor_after(Point::new(
 7978                invalidation_row_range.end,
 7979                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7980            ));
 7981
 7982        self.stale_edit_prediction_in_menu = None;
 7983        self.active_edit_prediction = Some(EditPredictionState {
 7984            inlay_ids,
 7985            completion,
 7986            completion_id: edit_prediction.id,
 7987            invalidation_range,
 7988        });
 7989
 7990        cx.notify();
 7991
 7992        Some(())
 7993    }
 7994
 7995    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7996        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7997    }
 7998
 7999    fn clear_tasks(&mut self) {
 8000        self.tasks.clear()
 8001    }
 8002
 8003    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8004        if self.tasks.insert(key, value).is_some() {
 8005            // This case should hopefully be rare, but just in case...
 8006            log::error!(
 8007                "multiple different run targets found on a single line, only the last target will be rendered"
 8008            )
 8009        }
 8010    }
 8011
 8012    /// Get all display points of breakpoints that will be rendered within editor
 8013    ///
 8014    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8015    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8016    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8017    fn active_breakpoints(
 8018        &self,
 8019        range: Range<DisplayRow>,
 8020        window: &mut Window,
 8021        cx: &mut Context<Self>,
 8022    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8023        let mut breakpoint_display_points = HashMap::default();
 8024
 8025        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8026            return breakpoint_display_points;
 8027        };
 8028
 8029        let snapshot = self.snapshot(window, cx);
 8030
 8031        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8032        let Some(project) = self.project() else {
 8033            return breakpoint_display_points;
 8034        };
 8035
 8036        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8037            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8038
 8039        for (buffer_snapshot, range, excerpt_id) in
 8040            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8041        {
 8042            let Some(buffer) = project
 8043                .read(cx)
 8044                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8045            else {
 8046                continue;
 8047            };
 8048            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8049                &buffer,
 8050                Some(
 8051                    buffer_snapshot.anchor_before(range.start)
 8052                        ..buffer_snapshot.anchor_after(range.end),
 8053                ),
 8054                buffer_snapshot,
 8055                cx,
 8056            );
 8057            for (breakpoint, state) in breakpoints {
 8058                let multi_buffer_anchor =
 8059                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8060                let position = multi_buffer_anchor
 8061                    .to_point(multi_buffer_snapshot)
 8062                    .to_display_point(&snapshot);
 8063
 8064                breakpoint_display_points.insert(
 8065                    position.row(),
 8066                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8067                );
 8068            }
 8069        }
 8070
 8071        breakpoint_display_points
 8072    }
 8073
 8074    fn breakpoint_context_menu(
 8075        &self,
 8076        anchor: Anchor,
 8077        window: &mut Window,
 8078        cx: &mut Context<Self>,
 8079    ) -> Entity<ui::ContextMenu> {
 8080        let weak_editor = cx.weak_entity();
 8081        let focus_handle = self.focus_handle(cx);
 8082
 8083        let row = self
 8084            .buffer
 8085            .read(cx)
 8086            .snapshot(cx)
 8087            .summary_for_anchor::<Point>(&anchor)
 8088            .row;
 8089
 8090        let breakpoint = self
 8091            .breakpoint_at_row(row, window, cx)
 8092            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8093
 8094        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8095            "Edit Log Breakpoint"
 8096        } else {
 8097            "Set Log Breakpoint"
 8098        };
 8099
 8100        let condition_breakpoint_msg = if breakpoint
 8101            .as_ref()
 8102            .is_some_and(|bp| bp.1.condition.is_some())
 8103        {
 8104            "Edit Condition Breakpoint"
 8105        } else {
 8106            "Set Condition Breakpoint"
 8107        };
 8108
 8109        let hit_condition_breakpoint_msg = if breakpoint
 8110            .as_ref()
 8111            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8112        {
 8113            "Edit Hit Condition Breakpoint"
 8114        } else {
 8115            "Set Hit Condition Breakpoint"
 8116        };
 8117
 8118        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8119            "Unset Breakpoint"
 8120        } else {
 8121            "Set Breakpoint"
 8122        };
 8123
 8124        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8125
 8126        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8127            BreakpointState::Enabled => Some("Disable"),
 8128            BreakpointState::Disabled => Some("Enable"),
 8129        });
 8130
 8131        let (anchor, breakpoint) =
 8132            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8133
 8134        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8135            menu.on_blur_subscription(Subscription::new(|| {}))
 8136                .context(focus_handle)
 8137                .when(run_to_cursor, |this| {
 8138                    let weak_editor = weak_editor.clone();
 8139                    this.entry("Run to cursor", None, move |window, cx| {
 8140                        weak_editor
 8141                            .update(cx, |editor, cx| {
 8142                                editor.change_selections(
 8143                                    SelectionEffects::no_scroll(),
 8144                                    window,
 8145                                    cx,
 8146                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8147                                );
 8148                            })
 8149                            .ok();
 8150
 8151                        window.dispatch_action(Box::new(RunToCursor), cx);
 8152                    })
 8153                    .separator()
 8154                })
 8155                .when_some(toggle_state_msg, |this, msg| {
 8156                    this.entry(msg, None, {
 8157                        let weak_editor = weak_editor.clone();
 8158                        let breakpoint = breakpoint.clone();
 8159                        move |_window, cx| {
 8160                            weak_editor
 8161                                .update(cx, |this, cx| {
 8162                                    this.edit_breakpoint_at_anchor(
 8163                                        anchor,
 8164                                        breakpoint.as_ref().clone(),
 8165                                        BreakpointEditAction::InvertState,
 8166                                        cx,
 8167                                    );
 8168                                })
 8169                                .log_err();
 8170                        }
 8171                    })
 8172                })
 8173                .entry(set_breakpoint_msg, None, {
 8174                    let weak_editor = weak_editor.clone();
 8175                    let breakpoint = breakpoint.clone();
 8176                    move |_window, cx| {
 8177                        weak_editor
 8178                            .update(cx, |this, cx| {
 8179                                this.edit_breakpoint_at_anchor(
 8180                                    anchor,
 8181                                    breakpoint.as_ref().clone(),
 8182                                    BreakpointEditAction::Toggle,
 8183                                    cx,
 8184                                );
 8185                            })
 8186                            .log_err();
 8187                    }
 8188                })
 8189                .entry(log_breakpoint_msg, None, {
 8190                    let breakpoint = breakpoint.clone();
 8191                    let weak_editor = weak_editor.clone();
 8192                    move |window, cx| {
 8193                        weak_editor
 8194                            .update(cx, |this, cx| {
 8195                                this.add_edit_breakpoint_block(
 8196                                    anchor,
 8197                                    breakpoint.as_ref(),
 8198                                    BreakpointPromptEditAction::Log,
 8199                                    window,
 8200                                    cx,
 8201                                );
 8202                            })
 8203                            .log_err();
 8204                    }
 8205                })
 8206                .entry(condition_breakpoint_msg, None, {
 8207                    let breakpoint = breakpoint.clone();
 8208                    let weak_editor = weak_editor.clone();
 8209                    move |window, cx| {
 8210                        weak_editor
 8211                            .update(cx, |this, cx| {
 8212                                this.add_edit_breakpoint_block(
 8213                                    anchor,
 8214                                    breakpoint.as_ref(),
 8215                                    BreakpointPromptEditAction::Condition,
 8216                                    window,
 8217                                    cx,
 8218                                );
 8219                            })
 8220                            .log_err();
 8221                    }
 8222                })
 8223                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8224                    weak_editor
 8225                        .update(cx, |this, cx| {
 8226                            this.add_edit_breakpoint_block(
 8227                                anchor,
 8228                                breakpoint.as_ref(),
 8229                                BreakpointPromptEditAction::HitCondition,
 8230                                window,
 8231                                cx,
 8232                            );
 8233                        })
 8234                        .log_err();
 8235                })
 8236        })
 8237    }
 8238
 8239    fn render_breakpoint(
 8240        &self,
 8241        position: Anchor,
 8242        row: DisplayRow,
 8243        breakpoint: &Breakpoint,
 8244        state: Option<BreakpointSessionState>,
 8245        cx: &mut Context<Self>,
 8246    ) -> IconButton {
 8247        let is_rejected = state.is_some_and(|s| !s.verified);
 8248        // Is it a breakpoint that shows up when hovering over gutter?
 8249        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8250            (false, false),
 8251            |PhantomBreakpointIndicator {
 8252                 is_active,
 8253                 display_row,
 8254                 collides_with_existing_breakpoint,
 8255             }| {
 8256                (
 8257                    is_active && display_row == row,
 8258                    collides_with_existing_breakpoint,
 8259                )
 8260            },
 8261        );
 8262
 8263        let (color, icon) = {
 8264            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8265                (false, false) => ui::IconName::DebugBreakpoint,
 8266                (true, false) => ui::IconName::DebugLogBreakpoint,
 8267                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8268                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8269            };
 8270
 8271            let color = if is_phantom {
 8272                Color::Hint
 8273            } else if is_rejected {
 8274                Color::Disabled
 8275            } else {
 8276                Color::Debugger
 8277            };
 8278
 8279            (color, icon)
 8280        };
 8281
 8282        let breakpoint = Arc::from(breakpoint.clone());
 8283
 8284        let alt_as_text = gpui::Keystroke {
 8285            modifiers: Modifiers::secondary_key(),
 8286            ..Default::default()
 8287        };
 8288        let primary_action_text = if breakpoint.is_disabled() {
 8289            "Enable breakpoint"
 8290        } else if is_phantom && !collides_with_existing {
 8291            "Set breakpoint"
 8292        } else {
 8293            "Unset breakpoint"
 8294        };
 8295        let focus_handle = self.focus_handle.clone();
 8296
 8297        let meta = if is_rejected {
 8298            SharedString::from("No executable code is associated with this line.")
 8299        } else if collides_with_existing && !breakpoint.is_disabled() {
 8300            SharedString::from(format!(
 8301                "{alt_as_text}-click to disable,\nright-click for more options."
 8302            ))
 8303        } else {
 8304            SharedString::from("Right-click for more options.")
 8305        };
 8306        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8307            .icon_size(IconSize::XSmall)
 8308            .size(ui::ButtonSize::None)
 8309            .when(is_rejected, |this| {
 8310                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8311            })
 8312            .icon_color(color)
 8313            .style(ButtonStyle::Transparent)
 8314            .on_click(cx.listener({
 8315                move |editor, event: &ClickEvent, window, cx| {
 8316                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8317                        BreakpointEditAction::InvertState
 8318                    } else {
 8319                        BreakpointEditAction::Toggle
 8320                    };
 8321
 8322                    window.focus(&editor.focus_handle(cx));
 8323                    editor.edit_breakpoint_at_anchor(
 8324                        position,
 8325                        breakpoint.as_ref().clone(),
 8326                        edit_action,
 8327                        cx,
 8328                    );
 8329                }
 8330            }))
 8331            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8332                editor.set_breakpoint_context_menu(
 8333                    row,
 8334                    Some(position),
 8335                    event.position(),
 8336                    window,
 8337                    cx,
 8338                );
 8339            }))
 8340            .tooltip(move |window, cx| {
 8341                Tooltip::with_meta_in(
 8342                    primary_action_text,
 8343                    Some(&ToggleBreakpoint),
 8344                    meta.clone(),
 8345                    &focus_handle,
 8346                    window,
 8347                    cx,
 8348                )
 8349            })
 8350    }
 8351
 8352    fn build_tasks_context(
 8353        project: &Entity<Project>,
 8354        buffer: &Entity<Buffer>,
 8355        buffer_row: u32,
 8356        tasks: &Arc<RunnableTasks>,
 8357        cx: &mut Context<Self>,
 8358    ) -> Task<Option<task::TaskContext>> {
 8359        let position = Point::new(buffer_row, tasks.column);
 8360        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8361        let location = Location {
 8362            buffer: buffer.clone(),
 8363            range: range_start..range_start,
 8364        };
 8365        // Fill in the environmental variables from the tree-sitter captures
 8366        let mut captured_task_variables = TaskVariables::default();
 8367        for (capture_name, value) in tasks.extra_variables.clone() {
 8368            captured_task_variables.insert(
 8369                task::VariableName::Custom(capture_name.into()),
 8370                value.clone(),
 8371            );
 8372        }
 8373        project.update(cx, |project, cx| {
 8374            project.task_store().update(cx, |task_store, cx| {
 8375                task_store.task_context_for_location(captured_task_variables, location, cx)
 8376            })
 8377        })
 8378    }
 8379
 8380    pub fn spawn_nearest_task(
 8381        &mut self,
 8382        action: &SpawnNearestTask,
 8383        window: &mut Window,
 8384        cx: &mut Context<Self>,
 8385    ) {
 8386        let Some((workspace, _)) = self.workspace.clone() else {
 8387            return;
 8388        };
 8389        let Some(project) = self.project.clone() else {
 8390            return;
 8391        };
 8392
 8393        // Try to find a closest, enclosing node using tree-sitter that has a task
 8394        let Some((buffer, buffer_row, tasks)) = self
 8395            .find_enclosing_node_task(cx)
 8396            // Or find the task that's closest in row-distance.
 8397            .or_else(|| self.find_closest_task(cx))
 8398        else {
 8399            return;
 8400        };
 8401
 8402        let reveal_strategy = action.reveal;
 8403        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8404        cx.spawn_in(window, async move |_, cx| {
 8405            let context = task_context.await?;
 8406            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8407
 8408            let resolved = &mut resolved_task.resolved;
 8409            resolved.reveal = reveal_strategy;
 8410
 8411            workspace
 8412                .update_in(cx, |workspace, window, cx| {
 8413                    workspace.schedule_resolved_task(
 8414                        task_source_kind,
 8415                        resolved_task,
 8416                        false,
 8417                        window,
 8418                        cx,
 8419                    );
 8420                })
 8421                .ok()
 8422        })
 8423        .detach();
 8424    }
 8425
 8426    fn find_closest_task(
 8427        &mut self,
 8428        cx: &mut Context<Self>,
 8429    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8430        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8431
 8432        let ((buffer_id, row), tasks) = self
 8433            .tasks
 8434            .iter()
 8435            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8436
 8437        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8438        let tasks = Arc::new(tasks.to_owned());
 8439        Some((buffer, *row, tasks))
 8440    }
 8441
 8442    fn find_enclosing_node_task(
 8443        &mut self,
 8444        cx: &mut Context<Self>,
 8445    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8446        let snapshot = self.buffer.read(cx).snapshot(cx);
 8447        let offset = self.selections.newest::<usize>(cx).head();
 8448        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8449        let buffer_id = excerpt.buffer().remote_id();
 8450
 8451        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8452        let mut cursor = layer.node().walk();
 8453
 8454        while cursor.goto_first_child_for_byte(offset).is_some() {
 8455            if cursor.node().end_byte() == offset {
 8456                cursor.goto_next_sibling();
 8457            }
 8458        }
 8459
 8460        // Ascend to the smallest ancestor that contains the range and has a task.
 8461        loop {
 8462            let node = cursor.node();
 8463            let node_range = node.byte_range();
 8464            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8465
 8466            // Check if this node contains our offset
 8467            if node_range.start <= offset && node_range.end >= offset {
 8468                // If it contains offset, check for task
 8469                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8470                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8471                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8472                }
 8473            }
 8474
 8475            if !cursor.goto_parent() {
 8476                break;
 8477            }
 8478        }
 8479        None
 8480    }
 8481
 8482    fn render_run_indicator(
 8483        &self,
 8484        _style: &EditorStyle,
 8485        is_active: bool,
 8486        row: DisplayRow,
 8487        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8488        cx: &mut Context<Self>,
 8489    ) -> IconButton {
 8490        let color = Color::Muted;
 8491        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8492
 8493        IconButton::new(
 8494            ("run_indicator", row.0 as usize),
 8495            ui::IconName::PlayOutlined,
 8496        )
 8497        .shape(ui::IconButtonShape::Square)
 8498        .icon_size(IconSize::XSmall)
 8499        .icon_color(color)
 8500        .toggle_state(is_active)
 8501        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8502            let quick_launch = match e {
 8503                ClickEvent::Keyboard(_) => true,
 8504                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8505            };
 8506
 8507            window.focus(&editor.focus_handle(cx));
 8508            editor.toggle_code_actions(
 8509                &ToggleCodeActions {
 8510                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8511                    quick_launch,
 8512                },
 8513                window,
 8514                cx,
 8515            );
 8516        }))
 8517        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8518            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8519        }))
 8520    }
 8521
 8522    pub fn context_menu_visible(&self) -> bool {
 8523        !self.edit_prediction_preview_is_active()
 8524            && self
 8525                .context_menu
 8526                .borrow()
 8527                .as_ref()
 8528                .is_some_and(|menu| menu.visible())
 8529    }
 8530
 8531    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8532        self.context_menu
 8533            .borrow()
 8534            .as_ref()
 8535            .map(|menu| menu.origin())
 8536    }
 8537
 8538    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8539        self.context_menu_options = Some(options);
 8540    }
 8541
 8542    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8543    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8544
 8545    fn render_edit_prediction_popover(
 8546        &mut self,
 8547        text_bounds: &Bounds<Pixels>,
 8548        content_origin: gpui::Point<Pixels>,
 8549        right_margin: Pixels,
 8550        editor_snapshot: &EditorSnapshot,
 8551        visible_row_range: Range<DisplayRow>,
 8552        scroll_top: f32,
 8553        scroll_bottom: f32,
 8554        line_layouts: &[LineWithInvisibles],
 8555        line_height: Pixels,
 8556        scroll_pixel_position: gpui::Point<Pixels>,
 8557        newest_selection_head: Option<DisplayPoint>,
 8558        editor_width: Pixels,
 8559        style: &EditorStyle,
 8560        window: &mut Window,
 8561        cx: &mut App,
 8562    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8563        if self.mode().is_minimap() {
 8564            return None;
 8565        }
 8566        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8567
 8568        if self.edit_prediction_visible_in_cursor_popover(true) {
 8569            return None;
 8570        }
 8571
 8572        match &active_edit_prediction.completion {
 8573            EditPrediction::Move { target, .. } => {
 8574                let target_display_point = target.to_display_point(editor_snapshot);
 8575
 8576                if self.edit_prediction_requires_modifier() {
 8577                    if !self.edit_prediction_preview_is_active() {
 8578                        return None;
 8579                    }
 8580
 8581                    self.render_edit_prediction_modifier_jump_popover(
 8582                        text_bounds,
 8583                        content_origin,
 8584                        visible_row_range,
 8585                        line_layouts,
 8586                        line_height,
 8587                        scroll_pixel_position,
 8588                        newest_selection_head,
 8589                        target_display_point,
 8590                        window,
 8591                        cx,
 8592                    )
 8593                } else {
 8594                    self.render_edit_prediction_eager_jump_popover(
 8595                        text_bounds,
 8596                        content_origin,
 8597                        editor_snapshot,
 8598                        visible_row_range,
 8599                        scroll_top,
 8600                        scroll_bottom,
 8601                        line_height,
 8602                        scroll_pixel_position,
 8603                        target_display_point,
 8604                        editor_width,
 8605                        window,
 8606                        cx,
 8607                    )
 8608                }
 8609            }
 8610            EditPrediction::Edit {
 8611                display_mode: EditDisplayMode::Inline,
 8612                ..
 8613            } => None,
 8614            EditPrediction::Edit {
 8615                display_mode: EditDisplayMode::TabAccept,
 8616                edits,
 8617                ..
 8618            } => {
 8619                let range = &edits.first()?.0;
 8620                let target_display_point = range.end.to_display_point(editor_snapshot);
 8621
 8622                self.render_edit_prediction_end_of_line_popover(
 8623                    "Accept",
 8624                    editor_snapshot,
 8625                    visible_row_range,
 8626                    target_display_point,
 8627                    line_height,
 8628                    scroll_pixel_position,
 8629                    content_origin,
 8630                    editor_width,
 8631                    window,
 8632                    cx,
 8633                )
 8634            }
 8635            EditPrediction::Edit {
 8636                edits,
 8637                edit_preview,
 8638                display_mode: EditDisplayMode::DiffPopover,
 8639                snapshot,
 8640            } => self.render_edit_prediction_diff_popover(
 8641                text_bounds,
 8642                content_origin,
 8643                right_margin,
 8644                editor_snapshot,
 8645                visible_row_range,
 8646                line_layouts,
 8647                line_height,
 8648                scroll_pixel_position,
 8649                newest_selection_head,
 8650                editor_width,
 8651                style,
 8652                edits,
 8653                edit_preview,
 8654                snapshot,
 8655                window,
 8656                cx,
 8657            ),
 8658        }
 8659    }
 8660
 8661    fn render_edit_prediction_modifier_jump_popover(
 8662        &mut self,
 8663        text_bounds: &Bounds<Pixels>,
 8664        content_origin: gpui::Point<Pixels>,
 8665        visible_row_range: Range<DisplayRow>,
 8666        line_layouts: &[LineWithInvisibles],
 8667        line_height: Pixels,
 8668        scroll_pixel_position: gpui::Point<Pixels>,
 8669        newest_selection_head: Option<DisplayPoint>,
 8670        target_display_point: DisplayPoint,
 8671        window: &mut Window,
 8672        cx: &mut App,
 8673    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8674        let scrolled_content_origin =
 8675            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8676
 8677        const SCROLL_PADDING_Y: Pixels = px(12.);
 8678
 8679        if target_display_point.row() < visible_row_range.start {
 8680            return self.render_edit_prediction_scroll_popover(
 8681                |_| SCROLL_PADDING_Y,
 8682                IconName::ArrowUp,
 8683                visible_row_range,
 8684                line_layouts,
 8685                newest_selection_head,
 8686                scrolled_content_origin,
 8687                window,
 8688                cx,
 8689            );
 8690        } else if target_display_point.row() >= visible_row_range.end {
 8691            return self.render_edit_prediction_scroll_popover(
 8692                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8693                IconName::ArrowDown,
 8694                visible_row_range,
 8695                line_layouts,
 8696                newest_selection_head,
 8697                scrolled_content_origin,
 8698                window,
 8699                cx,
 8700            );
 8701        }
 8702
 8703        const POLE_WIDTH: Pixels = px(2.);
 8704
 8705        let line_layout =
 8706            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8707        let target_column = target_display_point.column() as usize;
 8708
 8709        let target_x = line_layout.x_for_index(target_column);
 8710        let target_y =
 8711            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8712
 8713        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8714
 8715        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8716        border_color.l += 0.001;
 8717
 8718        let mut element = v_flex()
 8719            .items_end()
 8720            .when(flag_on_right, |el| el.items_start())
 8721            .child(if flag_on_right {
 8722                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8723                    .rounded_bl(px(0.))
 8724                    .rounded_tl(px(0.))
 8725                    .border_l_2()
 8726                    .border_color(border_color)
 8727            } else {
 8728                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8729                    .rounded_br(px(0.))
 8730                    .rounded_tr(px(0.))
 8731                    .border_r_2()
 8732                    .border_color(border_color)
 8733            })
 8734            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8735            .into_any();
 8736
 8737        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8738
 8739        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8740            - point(
 8741                if flag_on_right {
 8742                    POLE_WIDTH
 8743                } else {
 8744                    size.width - POLE_WIDTH
 8745                },
 8746                size.height - line_height,
 8747            );
 8748
 8749        origin.x = origin.x.max(content_origin.x);
 8750
 8751        element.prepaint_at(origin, window, cx);
 8752
 8753        Some((element, origin))
 8754    }
 8755
 8756    fn render_edit_prediction_scroll_popover(
 8757        &mut self,
 8758        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8759        scroll_icon: IconName,
 8760        visible_row_range: Range<DisplayRow>,
 8761        line_layouts: &[LineWithInvisibles],
 8762        newest_selection_head: Option<DisplayPoint>,
 8763        scrolled_content_origin: gpui::Point<Pixels>,
 8764        window: &mut Window,
 8765        cx: &mut App,
 8766    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8767        let mut element = self
 8768            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8769            .into_any();
 8770
 8771        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8772
 8773        let cursor = newest_selection_head?;
 8774        let cursor_row_layout =
 8775            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8776        let cursor_column = cursor.column() as usize;
 8777
 8778        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8779
 8780        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8781
 8782        element.prepaint_at(origin, window, cx);
 8783        Some((element, origin))
 8784    }
 8785
 8786    fn render_edit_prediction_eager_jump_popover(
 8787        &mut self,
 8788        text_bounds: &Bounds<Pixels>,
 8789        content_origin: gpui::Point<Pixels>,
 8790        editor_snapshot: &EditorSnapshot,
 8791        visible_row_range: Range<DisplayRow>,
 8792        scroll_top: f32,
 8793        scroll_bottom: f32,
 8794        line_height: Pixels,
 8795        scroll_pixel_position: gpui::Point<Pixels>,
 8796        target_display_point: DisplayPoint,
 8797        editor_width: Pixels,
 8798        window: &mut Window,
 8799        cx: &mut App,
 8800    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8801        if target_display_point.row().as_f32() < scroll_top {
 8802            let mut element = self
 8803                .render_edit_prediction_line_popover(
 8804                    "Jump to Edit",
 8805                    Some(IconName::ArrowUp),
 8806                    window,
 8807                    cx,
 8808                )?
 8809                .into_any();
 8810
 8811            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8812            let offset = point(
 8813                (text_bounds.size.width - size.width) / 2.,
 8814                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8815            );
 8816
 8817            let origin = text_bounds.origin + offset;
 8818            element.prepaint_at(origin, window, cx);
 8819            Some((element, origin))
 8820        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8821            let mut element = self
 8822                .render_edit_prediction_line_popover(
 8823                    "Jump to Edit",
 8824                    Some(IconName::ArrowDown),
 8825                    window,
 8826                    cx,
 8827                )?
 8828                .into_any();
 8829
 8830            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8831            let offset = point(
 8832                (text_bounds.size.width - size.width) / 2.,
 8833                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8834            );
 8835
 8836            let origin = text_bounds.origin + offset;
 8837            element.prepaint_at(origin, window, cx);
 8838            Some((element, origin))
 8839        } else {
 8840            self.render_edit_prediction_end_of_line_popover(
 8841                "Jump to Edit",
 8842                editor_snapshot,
 8843                visible_row_range,
 8844                target_display_point,
 8845                line_height,
 8846                scroll_pixel_position,
 8847                content_origin,
 8848                editor_width,
 8849                window,
 8850                cx,
 8851            )
 8852        }
 8853    }
 8854
 8855    fn render_edit_prediction_end_of_line_popover(
 8856        self: &mut Editor,
 8857        label: &'static str,
 8858        editor_snapshot: &EditorSnapshot,
 8859        visible_row_range: Range<DisplayRow>,
 8860        target_display_point: DisplayPoint,
 8861        line_height: Pixels,
 8862        scroll_pixel_position: gpui::Point<Pixels>,
 8863        content_origin: gpui::Point<Pixels>,
 8864        editor_width: Pixels,
 8865        window: &mut Window,
 8866        cx: &mut App,
 8867    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8868        let target_line_end = DisplayPoint::new(
 8869            target_display_point.row(),
 8870            editor_snapshot.line_len(target_display_point.row()),
 8871        );
 8872
 8873        let mut element = self
 8874            .render_edit_prediction_line_popover(label, None, window, cx)?
 8875            .into_any();
 8876
 8877        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8878
 8879        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8880
 8881        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8882        let mut origin = start_point
 8883            + line_origin
 8884            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8885        origin.x = origin.x.max(content_origin.x);
 8886
 8887        let max_x = content_origin.x + editor_width - size.width;
 8888
 8889        if origin.x > max_x {
 8890            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8891
 8892            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8893                origin.y += offset;
 8894                IconName::ArrowUp
 8895            } else {
 8896                origin.y -= offset;
 8897                IconName::ArrowDown
 8898            };
 8899
 8900            element = self
 8901                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8902                .into_any();
 8903
 8904            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8905
 8906            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8907        }
 8908
 8909        element.prepaint_at(origin, window, cx);
 8910        Some((element, origin))
 8911    }
 8912
 8913    fn render_edit_prediction_diff_popover(
 8914        self: &Editor,
 8915        text_bounds: &Bounds<Pixels>,
 8916        content_origin: gpui::Point<Pixels>,
 8917        right_margin: Pixels,
 8918        editor_snapshot: &EditorSnapshot,
 8919        visible_row_range: Range<DisplayRow>,
 8920        line_layouts: &[LineWithInvisibles],
 8921        line_height: Pixels,
 8922        scroll_pixel_position: gpui::Point<Pixels>,
 8923        newest_selection_head: Option<DisplayPoint>,
 8924        editor_width: Pixels,
 8925        style: &EditorStyle,
 8926        edits: &Vec<(Range<Anchor>, String)>,
 8927        edit_preview: &Option<language::EditPreview>,
 8928        snapshot: &language::BufferSnapshot,
 8929        window: &mut Window,
 8930        cx: &mut App,
 8931    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8932        let edit_start = edits
 8933            .first()
 8934            .unwrap()
 8935            .0
 8936            .start
 8937            .to_display_point(editor_snapshot);
 8938        let edit_end = edits
 8939            .last()
 8940            .unwrap()
 8941            .0
 8942            .end
 8943            .to_display_point(editor_snapshot);
 8944
 8945        let is_visible = visible_row_range.contains(&edit_start.row())
 8946            || visible_row_range.contains(&edit_end.row());
 8947        if !is_visible {
 8948            return None;
 8949        }
 8950
 8951        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8952            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8953        } else {
 8954            // Fallback for providers without edit_preview
 8955            crate::edit_prediction_fallback_text(edits, cx)
 8956        };
 8957
 8958        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8959        let line_count = highlighted_edits.text.lines().count();
 8960
 8961        const BORDER_WIDTH: Pixels = px(1.);
 8962
 8963        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8964        let has_keybind = keybind.is_some();
 8965
 8966        let mut element = h_flex()
 8967            .items_start()
 8968            .child(
 8969                h_flex()
 8970                    .bg(cx.theme().colors().editor_background)
 8971                    .border(BORDER_WIDTH)
 8972                    .shadow_xs()
 8973                    .border_color(cx.theme().colors().border)
 8974                    .rounded_l_lg()
 8975                    .when(line_count > 1, |el| el.rounded_br_lg())
 8976                    .pr_1()
 8977                    .child(styled_text),
 8978            )
 8979            .child(
 8980                h_flex()
 8981                    .h(line_height + BORDER_WIDTH * 2.)
 8982                    .px_1p5()
 8983                    .gap_1()
 8984                    // Workaround: For some reason, there's a gap if we don't do this
 8985                    .ml(-BORDER_WIDTH)
 8986                    .shadow(vec![gpui::BoxShadow {
 8987                        color: gpui::black().opacity(0.05),
 8988                        offset: point(px(1.), px(1.)),
 8989                        blur_radius: px(2.),
 8990                        spread_radius: px(0.),
 8991                    }])
 8992                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8993                    .border(BORDER_WIDTH)
 8994                    .border_color(cx.theme().colors().border)
 8995                    .rounded_r_lg()
 8996                    .id("edit_prediction_diff_popover_keybind")
 8997                    .when(!has_keybind, |el| {
 8998                        let status_colors = cx.theme().status();
 8999
 9000                        el.bg(status_colors.error_background)
 9001                            .border_color(status_colors.error.opacity(0.6))
 9002                            .child(Icon::new(IconName::Info).color(Color::Error))
 9003                            .cursor_default()
 9004                            .hoverable_tooltip(move |_window, cx| {
 9005                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9006                            })
 9007                    })
 9008                    .children(keybind),
 9009            )
 9010            .into_any();
 9011
 9012        let longest_row =
 9013            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9014        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9015            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9016        } else {
 9017            layout_line(
 9018                longest_row,
 9019                editor_snapshot,
 9020                style,
 9021                editor_width,
 9022                |_| false,
 9023                window,
 9024                cx,
 9025            )
 9026            .width
 9027        };
 9028
 9029        let viewport_bounds =
 9030            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9031                right: -right_margin,
 9032                ..Default::default()
 9033            });
 9034
 9035        let x_after_longest =
 9036            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9037                - scroll_pixel_position.x;
 9038
 9039        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9040
 9041        // Fully visible if it can be displayed within the window (allow overlapping other
 9042        // panes). However, this is only allowed if the popover starts within text_bounds.
 9043        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9044            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9045
 9046        let mut origin = if can_position_to_the_right {
 9047            point(
 9048                x_after_longest,
 9049                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9050                    - scroll_pixel_position.y,
 9051            )
 9052        } else {
 9053            let cursor_row = newest_selection_head.map(|head| head.row());
 9054            let above_edit = edit_start
 9055                .row()
 9056                .0
 9057                .checked_sub(line_count as u32)
 9058                .map(DisplayRow);
 9059            let below_edit = Some(edit_end.row() + 1);
 9060            let above_cursor =
 9061                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9062            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9063
 9064            // Place the edit popover adjacent to the edit if there is a location
 9065            // available that is onscreen and does not obscure the cursor. Otherwise,
 9066            // place it adjacent to the cursor.
 9067            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9068                .into_iter()
 9069                .flatten()
 9070                .find(|&start_row| {
 9071                    let end_row = start_row + line_count as u32;
 9072                    visible_row_range.contains(&start_row)
 9073                        && visible_row_range.contains(&end_row)
 9074                        && cursor_row
 9075                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9076                })?;
 9077
 9078            content_origin
 9079                + point(
 9080                    -scroll_pixel_position.x,
 9081                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9082                )
 9083        };
 9084
 9085        origin.x -= BORDER_WIDTH;
 9086
 9087        window.defer_draw(element, origin, 1);
 9088
 9089        // Do not return an element, since it will already be drawn due to defer_draw.
 9090        None
 9091    }
 9092
 9093    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9094        px(30.)
 9095    }
 9096
 9097    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9098        if self.read_only(cx) {
 9099            cx.theme().players().read_only()
 9100        } else {
 9101            self.style.as_ref().unwrap().local_player
 9102        }
 9103    }
 9104
 9105    fn render_edit_prediction_accept_keybind(
 9106        &self,
 9107        window: &mut Window,
 9108        cx: &App,
 9109    ) -> Option<AnyElement> {
 9110        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9111        let accept_keystroke = accept_binding.keystroke()?;
 9112
 9113        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9114
 9115        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9116            Color::Accent
 9117        } else {
 9118            Color::Muted
 9119        };
 9120
 9121        h_flex()
 9122            .px_0p5()
 9123            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9124            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9125            .text_size(TextSize::XSmall.rems(cx))
 9126            .child(h_flex().children(ui::render_modifiers(
 9127                accept_keystroke.modifiers(),
 9128                PlatformStyle::platform(),
 9129                Some(modifiers_color),
 9130                Some(IconSize::XSmall.rems().into()),
 9131                true,
 9132            )))
 9133            .when(is_platform_style_mac, |parent| {
 9134                parent.child(accept_keystroke.key().to_string())
 9135            })
 9136            .when(!is_platform_style_mac, |parent| {
 9137                parent.child(
 9138                    Key::new(
 9139                        util::capitalize(accept_keystroke.key()),
 9140                        Some(Color::Default),
 9141                    )
 9142                    .size(Some(IconSize::XSmall.rems().into())),
 9143                )
 9144            })
 9145            .into_any()
 9146            .into()
 9147    }
 9148
 9149    fn render_edit_prediction_line_popover(
 9150        &self,
 9151        label: impl Into<SharedString>,
 9152        icon: Option<IconName>,
 9153        window: &mut Window,
 9154        cx: &App,
 9155    ) -> Option<Stateful<Div>> {
 9156        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9157
 9158        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9159        let has_keybind = keybind.is_some();
 9160
 9161        let result = h_flex()
 9162            .id("ep-line-popover")
 9163            .py_0p5()
 9164            .pl_1()
 9165            .pr(padding_right)
 9166            .gap_1()
 9167            .rounded_md()
 9168            .border_1()
 9169            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9170            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9171            .shadow_xs()
 9172            .when(!has_keybind, |el| {
 9173                let status_colors = cx.theme().status();
 9174
 9175                el.bg(status_colors.error_background)
 9176                    .border_color(status_colors.error.opacity(0.6))
 9177                    .pl_2()
 9178                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9179                    .cursor_default()
 9180                    .hoverable_tooltip(move |_window, cx| {
 9181                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9182                    })
 9183            })
 9184            .children(keybind)
 9185            .child(
 9186                Label::new(label)
 9187                    .size(LabelSize::Small)
 9188                    .when(!has_keybind, |el| {
 9189                        el.color(cx.theme().status().error.into()).strikethrough()
 9190                    }),
 9191            )
 9192            .when(!has_keybind, |el| {
 9193                el.child(
 9194                    h_flex().ml_1().child(
 9195                        Icon::new(IconName::Info)
 9196                            .size(IconSize::Small)
 9197                            .color(cx.theme().status().error.into()),
 9198                    ),
 9199                )
 9200            })
 9201            .when_some(icon, |element, icon| {
 9202                element.child(
 9203                    div()
 9204                        .mt(px(1.5))
 9205                        .child(Icon::new(icon).size(IconSize::Small)),
 9206                )
 9207            });
 9208
 9209        Some(result)
 9210    }
 9211
 9212    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9213        let accent_color = cx.theme().colors().text_accent;
 9214        let editor_bg_color = cx.theme().colors().editor_background;
 9215        editor_bg_color.blend(accent_color.opacity(0.1))
 9216    }
 9217
 9218    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9219        let accent_color = cx.theme().colors().text_accent;
 9220        let editor_bg_color = cx.theme().colors().editor_background;
 9221        editor_bg_color.blend(accent_color.opacity(0.6))
 9222    }
 9223    fn get_prediction_provider_icon_name(
 9224        provider: &Option<RegisteredEditPredictionProvider>,
 9225    ) -> IconName {
 9226        match provider {
 9227            Some(provider) => match provider.provider.name() {
 9228                "copilot" => IconName::Copilot,
 9229                "supermaven" => IconName::Supermaven,
 9230                _ => IconName::ZedPredict,
 9231            },
 9232            None => IconName::ZedPredict,
 9233        }
 9234    }
 9235
 9236    fn render_edit_prediction_cursor_popover(
 9237        &self,
 9238        min_width: Pixels,
 9239        max_width: Pixels,
 9240        cursor_point: Point,
 9241        style: &EditorStyle,
 9242        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9243        _window: &Window,
 9244        cx: &mut Context<Editor>,
 9245    ) -> Option<AnyElement> {
 9246        let provider = self.edit_prediction_provider.as_ref()?;
 9247        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9248
 9249        let is_refreshing = provider.provider.is_refreshing(cx);
 9250
 9251        fn pending_completion_container(icon: IconName) -> Div {
 9252            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9253        }
 9254
 9255        let completion = match &self.active_edit_prediction {
 9256            Some(prediction) => {
 9257                if !self.has_visible_completions_menu() {
 9258                    const RADIUS: Pixels = px(6.);
 9259                    const BORDER_WIDTH: Pixels = px(1.);
 9260
 9261                    return Some(
 9262                        h_flex()
 9263                            .elevation_2(cx)
 9264                            .border(BORDER_WIDTH)
 9265                            .border_color(cx.theme().colors().border)
 9266                            .when(accept_keystroke.is_none(), |el| {
 9267                                el.border_color(cx.theme().status().error)
 9268                            })
 9269                            .rounded(RADIUS)
 9270                            .rounded_tl(px(0.))
 9271                            .overflow_hidden()
 9272                            .child(div().px_1p5().child(match &prediction.completion {
 9273                                EditPrediction::Move { target, snapshot } => {
 9274                                    use text::ToPoint as _;
 9275                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9276                                    {
 9277                                        Icon::new(IconName::ZedPredictDown)
 9278                                    } else {
 9279                                        Icon::new(IconName::ZedPredictUp)
 9280                                    }
 9281                                }
 9282                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9283                            }))
 9284                            .child(
 9285                                h_flex()
 9286                                    .gap_1()
 9287                                    .py_1()
 9288                                    .px_2()
 9289                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9290                                    .border_l_1()
 9291                                    .border_color(cx.theme().colors().border)
 9292                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9293                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9294                                        el.child(
 9295                                            Label::new("Hold")
 9296                                                .size(LabelSize::Small)
 9297                                                .when(accept_keystroke.is_none(), |el| {
 9298                                                    el.strikethrough()
 9299                                                })
 9300                                                .line_height_style(LineHeightStyle::UiLabel),
 9301                                        )
 9302                                    })
 9303                                    .id("edit_prediction_cursor_popover_keybind")
 9304                                    .when(accept_keystroke.is_none(), |el| {
 9305                                        let status_colors = cx.theme().status();
 9306
 9307                                        el.bg(status_colors.error_background)
 9308                                            .border_color(status_colors.error.opacity(0.6))
 9309                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9310                                            .cursor_default()
 9311                                            .hoverable_tooltip(move |_window, cx| {
 9312                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9313                                                    .into()
 9314                                            })
 9315                                    })
 9316                                    .when_some(
 9317                                        accept_keystroke.as_ref(),
 9318                                        |el, accept_keystroke| {
 9319                                            el.child(h_flex().children(ui::render_modifiers(
 9320                                                accept_keystroke.modifiers(),
 9321                                                PlatformStyle::platform(),
 9322                                                Some(Color::Default),
 9323                                                Some(IconSize::XSmall.rems().into()),
 9324                                                false,
 9325                                            )))
 9326                                        },
 9327                                    ),
 9328                            )
 9329                            .into_any(),
 9330                    );
 9331                }
 9332
 9333                self.render_edit_prediction_cursor_popover_preview(
 9334                    prediction,
 9335                    cursor_point,
 9336                    style,
 9337                    cx,
 9338                )?
 9339            }
 9340
 9341            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9342                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9343                    stale_completion,
 9344                    cursor_point,
 9345                    style,
 9346                    cx,
 9347                )?,
 9348
 9349                None => pending_completion_container(provider_icon)
 9350                    .child(Label::new("...").size(LabelSize::Small)),
 9351            },
 9352
 9353            None => pending_completion_container(provider_icon)
 9354                .child(Label::new("...").size(LabelSize::Small)),
 9355        };
 9356
 9357        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9358            completion
 9359                .with_animation(
 9360                    "loading-completion",
 9361                    Animation::new(Duration::from_secs(2))
 9362                        .repeat()
 9363                        .with_easing(pulsating_between(0.4, 0.8)),
 9364                    |label, delta| label.opacity(delta),
 9365                )
 9366                .into_any_element()
 9367        } else {
 9368            completion.into_any_element()
 9369        };
 9370
 9371        let has_completion = self.active_edit_prediction.is_some();
 9372
 9373        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9374        Some(
 9375            h_flex()
 9376                .min_w(min_width)
 9377                .max_w(max_width)
 9378                .flex_1()
 9379                .elevation_2(cx)
 9380                .border_color(cx.theme().colors().border)
 9381                .child(
 9382                    div()
 9383                        .flex_1()
 9384                        .py_1()
 9385                        .px_2()
 9386                        .overflow_hidden()
 9387                        .child(completion),
 9388                )
 9389                .when_some(accept_keystroke, |el, accept_keystroke| {
 9390                    if !accept_keystroke.modifiers().modified() {
 9391                        return el;
 9392                    }
 9393
 9394                    el.child(
 9395                        h_flex()
 9396                            .h_full()
 9397                            .border_l_1()
 9398                            .rounded_r_lg()
 9399                            .border_color(cx.theme().colors().border)
 9400                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9401                            .gap_1()
 9402                            .py_1()
 9403                            .px_2()
 9404                            .child(
 9405                                h_flex()
 9406                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9407                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9408                                    .child(h_flex().children(ui::render_modifiers(
 9409                                        accept_keystroke.modifiers(),
 9410                                        PlatformStyle::platform(),
 9411                                        Some(if !has_completion {
 9412                                            Color::Muted
 9413                                        } else {
 9414                                            Color::Default
 9415                                        }),
 9416                                        None,
 9417                                        false,
 9418                                    ))),
 9419                            )
 9420                            .child(Label::new("Preview").into_any_element())
 9421                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9422                    )
 9423                })
 9424                .into_any(),
 9425        )
 9426    }
 9427
 9428    fn render_edit_prediction_cursor_popover_preview(
 9429        &self,
 9430        completion: &EditPredictionState,
 9431        cursor_point: Point,
 9432        style: &EditorStyle,
 9433        cx: &mut Context<Editor>,
 9434    ) -> Option<Div> {
 9435        use text::ToPoint as _;
 9436
 9437        fn render_relative_row_jump(
 9438            prefix: impl Into<String>,
 9439            current_row: u32,
 9440            target_row: u32,
 9441        ) -> Div {
 9442            let (row_diff, arrow) = if target_row < current_row {
 9443                (current_row - target_row, IconName::ArrowUp)
 9444            } else {
 9445                (target_row - current_row, IconName::ArrowDown)
 9446            };
 9447
 9448            h_flex()
 9449                .child(
 9450                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9451                        .color(Color::Muted)
 9452                        .size(LabelSize::Small),
 9453                )
 9454                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9455        }
 9456
 9457        let supports_jump = self
 9458            .edit_prediction_provider
 9459            .as_ref()
 9460            .map(|provider| provider.provider.supports_jump_to_edit())
 9461            .unwrap_or(true);
 9462
 9463        match &completion.completion {
 9464            EditPrediction::Move {
 9465                target, snapshot, ..
 9466            } => {
 9467                if !supports_jump {
 9468                    return None;
 9469                }
 9470
 9471                Some(
 9472                    h_flex()
 9473                        .px_2()
 9474                        .gap_2()
 9475                        .flex_1()
 9476                        .child(
 9477                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9478                                Icon::new(IconName::ZedPredictDown)
 9479                            } else {
 9480                                Icon::new(IconName::ZedPredictUp)
 9481                            },
 9482                        )
 9483                        .child(Label::new("Jump to Edit")),
 9484                )
 9485            }
 9486
 9487            EditPrediction::Edit {
 9488                edits,
 9489                edit_preview,
 9490                snapshot,
 9491                display_mode: _,
 9492            } => {
 9493                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9494
 9495                let (highlighted_edits, has_more_lines) =
 9496                    if let Some(edit_preview) = edit_preview.as_ref() {
 9497                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9498                            .first_line_preview()
 9499                    } else {
 9500                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9501                    };
 9502
 9503                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9504                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9505
 9506                let preview = h_flex()
 9507                    .gap_1()
 9508                    .min_w_16()
 9509                    .child(styled_text)
 9510                    .when(has_more_lines, |parent| parent.child(""));
 9511
 9512                let left = if supports_jump && first_edit_row != cursor_point.row {
 9513                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9514                        .into_any_element()
 9515                } else {
 9516                    let icon_name =
 9517                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9518                    Icon::new(icon_name).into_any_element()
 9519                };
 9520
 9521                Some(
 9522                    h_flex()
 9523                        .h_full()
 9524                        .flex_1()
 9525                        .gap_2()
 9526                        .pr_1()
 9527                        .overflow_x_hidden()
 9528                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9529                        .child(left)
 9530                        .child(preview),
 9531                )
 9532            }
 9533        }
 9534    }
 9535
 9536    pub fn render_context_menu(
 9537        &self,
 9538        style: &EditorStyle,
 9539        max_height_in_lines: u32,
 9540        window: &mut Window,
 9541        cx: &mut Context<Editor>,
 9542    ) -> Option<AnyElement> {
 9543        let menu = self.context_menu.borrow();
 9544        let menu = menu.as_ref()?;
 9545        if !menu.visible() {
 9546            return None;
 9547        };
 9548        Some(menu.render(style, max_height_in_lines, window, cx))
 9549    }
 9550
 9551    fn render_context_menu_aside(
 9552        &mut self,
 9553        max_size: Size<Pixels>,
 9554        window: &mut Window,
 9555        cx: &mut Context<Editor>,
 9556    ) -> Option<AnyElement> {
 9557        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9558            if menu.visible() {
 9559                menu.render_aside(max_size, window, cx)
 9560            } else {
 9561                None
 9562            }
 9563        })
 9564    }
 9565
 9566    fn hide_context_menu(
 9567        &mut self,
 9568        window: &mut Window,
 9569        cx: &mut Context<Self>,
 9570    ) -> Option<CodeContextMenu> {
 9571        cx.notify();
 9572        self.completion_tasks.clear();
 9573        let context_menu = self.context_menu.borrow_mut().take();
 9574        self.stale_edit_prediction_in_menu.take();
 9575        self.update_visible_edit_prediction(window, cx);
 9576        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9577            && let Some(completion_provider) = &self.completion_provider
 9578        {
 9579            completion_provider.selection_changed(None, window, cx);
 9580        }
 9581        context_menu
 9582    }
 9583
 9584    fn show_snippet_choices(
 9585        &mut self,
 9586        choices: &Vec<String>,
 9587        selection: Range<Anchor>,
 9588        cx: &mut Context<Self>,
 9589    ) {
 9590        let Some((_, buffer, _)) = self
 9591            .buffer()
 9592            .read(cx)
 9593            .excerpt_containing(selection.start, cx)
 9594        else {
 9595            return;
 9596        };
 9597        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9598        else {
 9599            return;
 9600        };
 9601        if buffer != end_buffer {
 9602            log::error!("expected anchor range to have matching buffer IDs");
 9603            return;
 9604        }
 9605
 9606        let id = post_inc(&mut self.next_completion_id);
 9607        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9608        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9609            CompletionsMenu::new_snippet_choices(
 9610                id,
 9611                true,
 9612                choices,
 9613                selection,
 9614                buffer,
 9615                snippet_sort_order,
 9616            ),
 9617        ));
 9618    }
 9619
 9620    pub fn insert_snippet(
 9621        &mut self,
 9622        insertion_ranges: &[Range<usize>],
 9623        snippet: Snippet,
 9624        window: &mut Window,
 9625        cx: &mut Context<Self>,
 9626    ) -> Result<()> {
 9627        struct Tabstop<T> {
 9628            is_end_tabstop: bool,
 9629            ranges: Vec<Range<T>>,
 9630            choices: Option<Vec<String>>,
 9631        }
 9632
 9633        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9634            let snippet_text: Arc<str> = snippet.text.clone().into();
 9635            let edits = insertion_ranges
 9636                .iter()
 9637                .cloned()
 9638                .map(|range| (range, snippet_text.clone()));
 9639            let autoindent_mode = AutoindentMode::Block {
 9640                original_indent_columns: Vec::new(),
 9641            };
 9642            buffer.edit(edits, Some(autoindent_mode), cx);
 9643
 9644            let snapshot = &*buffer.read(cx);
 9645            let snippet = &snippet;
 9646            snippet
 9647                .tabstops
 9648                .iter()
 9649                .map(|tabstop| {
 9650                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9651                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9652                    });
 9653                    let mut tabstop_ranges = tabstop
 9654                        .ranges
 9655                        .iter()
 9656                        .flat_map(|tabstop_range| {
 9657                            let mut delta = 0_isize;
 9658                            insertion_ranges.iter().map(move |insertion_range| {
 9659                                let insertion_start = insertion_range.start as isize + delta;
 9660                                delta +=
 9661                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9662
 9663                                let start = ((insertion_start + tabstop_range.start) as usize)
 9664                                    .min(snapshot.len());
 9665                                let end = ((insertion_start + tabstop_range.end) as usize)
 9666                                    .min(snapshot.len());
 9667                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9668                            })
 9669                        })
 9670                        .collect::<Vec<_>>();
 9671                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9672
 9673                    Tabstop {
 9674                        is_end_tabstop,
 9675                        ranges: tabstop_ranges,
 9676                        choices: tabstop.choices.clone(),
 9677                    }
 9678                })
 9679                .collect::<Vec<_>>()
 9680        });
 9681        if let Some(tabstop) = tabstops.first() {
 9682            self.change_selections(Default::default(), window, cx, |s| {
 9683                // Reverse order so that the first range is the newest created selection.
 9684                // Completions will use it and autoscroll will prioritize it.
 9685                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9686            });
 9687
 9688            if let Some(choices) = &tabstop.choices
 9689                && let Some(selection) = tabstop.ranges.first()
 9690            {
 9691                self.show_snippet_choices(choices, selection.clone(), cx)
 9692            }
 9693
 9694            // If we're already at the last tabstop and it's at the end of the snippet,
 9695            // we're done, we don't need to keep the state around.
 9696            if !tabstop.is_end_tabstop {
 9697                let choices = tabstops
 9698                    .iter()
 9699                    .map(|tabstop| tabstop.choices.clone())
 9700                    .collect();
 9701
 9702                let ranges = tabstops
 9703                    .into_iter()
 9704                    .map(|tabstop| tabstop.ranges)
 9705                    .collect::<Vec<_>>();
 9706
 9707                self.snippet_stack.push(SnippetState {
 9708                    active_index: 0,
 9709                    ranges,
 9710                    choices,
 9711                });
 9712            }
 9713
 9714            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9715            if self.autoclose_regions.is_empty() {
 9716                let snapshot = self.buffer.read(cx).snapshot(cx);
 9717                let mut all_selections = self.selections.all::<Point>(cx);
 9718                for selection in &mut all_selections {
 9719                    let selection_head = selection.head();
 9720                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9721                        continue;
 9722                    };
 9723
 9724                    let mut bracket_pair = None;
 9725                    let max_lookup_length = scope
 9726                        .brackets()
 9727                        .map(|(pair, _)| {
 9728                            pair.start
 9729                                .as_str()
 9730                                .chars()
 9731                                .count()
 9732                                .max(pair.end.as_str().chars().count())
 9733                        })
 9734                        .max();
 9735                    if let Some(max_lookup_length) = max_lookup_length {
 9736                        let next_text = snapshot
 9737                            .chars_at(selection_head)
 9738                            .take(max_lookup_length)
 9739                            .collect::<String>();
 9740                        let prev_text = snapshot
 9741                            .reversed_chars_at(selection_head)
 9742                            .take(max_lookup_length)
 9743                            .collect::<String>();
 9744
 9745                        for (pair, enabled) in scope.brackets() {
 9746                            if enabled
 9747                                && pair.close
 9748                                && prev_text.starts_with(pair.start.as_str())
 9749                                && next_text.starts_with(pair.end.as_str())
 9750                            {
 9751                                bracket_pair = Some(pair.clone());
 9752                                break;
 9753                            }
 9754                        }
 9755                    }
 9756
 9757                    if let Some(pair) = bracket_pair {
 9758                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9759                        let autoclose_enabled =
 9760                            self.use_autoclose && snapshot_settings.use_autoclose;
 9761                        if autoclose_enabled {
 9762                            let start = snapshot.anchor_after(selection_head);
 9763                            let end = snapshot.anchor_after(selection_head);
 9764                            self.autoclose_regions.push(AutocloseRegion {
 9765                                selection_id: selection.id,
 9766                                range: start..end,
 9767                                pair,
 9768                            });
 9769                        }
 9770                    }
 9771                }
 9772            }
 9773        }
 9774        Ok(())
 9775    }
 9776
 9777    pub fn move_to_next_snippet_tabstop(
 9778        &mut self,
 9779        window: &mut Window,
 9780        cx: &mut Context<Self>,
 9781    ) -> bool {
 9782        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9783    }
 9784
 9785    pub fn move_to_prev_snippet_tabstop(
 9786        &mut self,
 9787        window: &mut Window,
 9788        cx: &mut Context<Self>,
 9789    ) -> bool {
 9790        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9791    }
 9792
 9793    pub fn move_to_snippet_tabstop(
 9794        &mut self,
 9795        bias: Bias,
 9796        window: &mut Window,
 9797        cx: &mut Context<Self>,
 9798    ) -> bool {
 9799        if let Some(mut snippet) = self.snippet_stack.pop() {
 9800            match bias {
 9801                Bias::Left => {
 9802                    if snippet.active_index > 0 {
 9803                        snippet.active_index -= 1;
 9804                    } else {
 9805                        self.snippet_stack.push(snippet);
 9806                        return false;
 9807                    }
 9808                }
 9809                Bias::Right => {
 9810                    if snippet.active_index + 1 < snippet.ranges.len() {
 9811                        snippet.active_index += 1;
 9812                    } else {
 9813                        self.snippet_stack.push(snippet);
 9814                        return false;
 9815                    }
 9816                }
 9817            }
 9818            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9819                self.change_selections(Default::default(), window, cx, |s| {
 9820                    // Reverse order so that the first range is the newest created selection.
 9821                    // Completions will use it and autoscroll will prioritize it.
 9822                    s.select_ranges(current_ranges.iter().rev().cloned())
 9823                });
 9824
 9825                if let Some(choices) = &snippet.choices[snippet.active_index]
 9826                    && let Some(selection) = current_ranges.first()
 9827                {
 9828                    self.show_snippet_choices(choices, selection.clone(), cx);
 9829                }
 9830
 9831                // If snippet state is not at the last tabstop, push it back on the stack
 9832                if snippet.active_index + 1 < snippet.ranges.len() {
 9833                    self.snippet_stack.push(snippet);
 9834                }
 9835                return true;
 9836            }
 9837        }
 9838
 9839        false
 9840    }
 9841
 9842    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9843        self.transact(window, cx, |this, window, cx| {
 9844            this.select_all(&SelectAll, window, cx);
 9845            this.insert("", window, cx);
 9846        });
 9847    }
 9848
 9849    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9850        if self.read_only(cx) {
 9851            return;
 9852        }
 9853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9854        self.transact(window, cx, |this, window, cx| {
 9855            this.select_autoclose_pair(window, cx);
 9856            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9857            if !this.linked_edit_ranges.is_empty() {
 9858                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9859                let snapshot = this.buffer.read(cx).snapshot(cx);
 9860
 9861                for selection in selections.iter() {
 9862                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9863                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9864                    if selection_start.buffer_id != selection_end.buffer_id {
 9865                        continue;
 9866                    }
 9867                    if let Some(ranges) =
 9868                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9869                    {
 9870                        for (buffer, entries) in ranges {
 9871                            linked_ranges.entry(buffer).or_default().extend(entries);
 9872                        }
 9873                    }
 9874                }
 9875            }
 9876
 9877            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9878            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9879            for selection in &mut selections {
 9880                if selection.is_empty() {
 9881                    let old_head = selection.head();
 9882                    let mut new_head =
 9883                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9884                            .to_point(&display_map);
 9885                    if let Some((buffer, line_buffer_range)) = display_map
 9886                        .buffer_snapshot
 9887                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9888                    {
 9889                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9890                        let indent_len = match indent_size.kind {
 9891                            IndentKind::Space => {
 9892                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9893                            }
 9894                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9895                        };
 9896                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9897                            let indent_len = indent_len.get();
 9898                            new_head = cmp::min(
 9899                                new_head,
 9900                                MultiBufferPoint::new(
 9901                                    old_head.row,
 9902                                    ((old_head.column - 1) / indent_len) * indent_len,
 9903                                ),
 9904                            );
 9905                        }
 9906                    }
 9907
 9908                    selection.set_head(new_head, SelectionGoal::None);
 9909                }
 9910            }
 9911
 9912            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9913            this.insert("", window, cx);
 9914            let empty_str: Arc<str> = Arc::from("");
 9915            for (buffer, edits) in linked_ranges {
 9916                let snapshot = buffer.read(cx).snapshot();
 9917                use text::ToPoint as TP;
 9918
 9919                let edits = edits
 9920                    .into_iter()
 9921                    .map(|range| {
 9922                        let end_point = TP::to_point(&range.end, &snapshot);
 9923                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9924
 9925                        if end_point == start_point {
 9926                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9927                                .saturating_sub(1);
 9928                            start_point =
 9929                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9930                        };
 9931
 9932                        (start_point..end_point, empty_str.clone())
 9933                    })
 9934                    .sorted_by_key(|(range, _)| range.start)
 9935                    .collect::<Vec<_>>();
 9936                buffer.update(cx, |this, cx| {
 9937                    this.edit(edits, None, cx);
 9938                })
 9939            }
 9940            this.refresh_edit_prediction(true, false, window, cx);
 9941            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9942        });
 9943    }
 9944
 9945    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9946        if self.read_only(cx) {
 9947            return;
 9948        }
 9949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9950        self.transact(window, cx, |this, window, cx| {
 9951            this.change_selections(Default::default(), window, cx, |s| {
 9952                s.move_with(|map, selection| {
 9953                    if selection.is_empty() {
 9954                        let cursor = movement::right(map, selection.head());
 9955                        selection.end = cursor;
 9956                        selection.reversed = true;
 9957                        selection.goal = SelectionGoal::None;
 9958                    }
 9959                })
 9960            });
 9961            this.insert("", window, cx);
 9962            this.refresh_edit_prediction(true, false, window, cx);
 9963        });
 9964    }
 9965
 9966    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9967        if self.mode.is_single_line() {
 9968            cx.propagate();
 9969            return;
 9970        }
 9971
 9972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9973        if self.move_to_prev_snippet_tabstop(window, cx) {
 9974            return;
 9975        }
 9976        self.outdent(&Outdent, window, cx);
 9977    }
 9978
 9979    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9980        if self.mode.is_single_line() {
 9981            cx.propagate();
 9982            return;
 9983        }
 9984
 9985        if self.move_to_next_snippet_tabstop(window, cx) {
 9986            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987            return;
 9988        }
 9989        if self.read_only(cx) {
 9990            return;
 9991        }
 9992        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9993        let mut selections = self.selections.all_adjusted(cx);
 9994        let buffer = self.buffer.read(cx);
 9995        let snapshot = buffer.snapshot(cx);
 9996        let rows_iter = selections.iter().map(|s| s.head().row);
 9997        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9998
 9999        let has_some_cursor_in_whitespace = selections
10000            .iter()
10001            .filter(|selection| selection.is_empty())
10002            .any(|selection| {
10003                let cursor = selection.head();
10004                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10005                cursor.column < current_indent.len
10006            });
10007
10008        let mut edits = Vec::new();
10009        let mut prev_edited_row = 0;
10010        let mut row_delta = 0;
10011        for selection in &mut selections {
10012            if selection.start.row != prev_edited_row {
10013                row_delta = 0;
10014            }
10015            prev_edited_row = selection.end.row;
10016
10017            // If the selection is non-empty, then increase the indentation of the selected lines.
10018            if !selection.is_empty() {
10019                row_delta =
10020                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10021                continue;
10022            }
10023
10024            let cursor = selection.head();
10025            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10026            if let Some(suggested_indent) =
10027                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10028            {
10029                // Don't do anything if already at suggested indent
10030                // and there is any other cursor which is not
10031                if has_some_cursor_in_whitespace
10032                    && cursor.column == current_indent.len
10033                    && current_indent.len == suggested_indent.len
10034                {
10035                    continue;
10036                }
10037
10038                // Adjust line and move cursor to suggested indent
10039                // if cursor is not at suggested indent
10040                if cursor.column < suggested_indent.len
10041                    && cursor.column <= current_indent.len
10042                    && current_indent.len <= suggested_indent.len
10043                {
10044                    selection.start = Point::new(cursor.row, suggested_indent.len);
10045                    selection.end = selection.start;
10046                    if row_delta == 0 {
10047                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10048                            cursor.row,
10049                            current_indent,
10050                            suggested_indent,
10051                        ));
10052                        row_delta = suggested_indent.len - current_indent.len;
10053                    }
10054                    continue;
10055                }
10056
10057                // If current indent is more than suggested indent
10058                // only move cursor to current indent and skip indent
10059                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10060                    selection.start = Point::new(cursor.row, current_indent.len);
10061                    selection.end = selection.start;
10062                    continue;
10063                }
10064            }
10065
10066            // Otherwise, insert a hard or soft tab.
10067            let settings = buffer.language_settings_at(cursor, cx);
10068            let tab_size = if settings.hard_tabs {
10069                IndentSize::tab()
10070            } else {
10071                let tab_size = settings.tab_size.get();
10072                let indent_remainder = snapshot
10073                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10074                    .flat_map(str::chars)
10075                    .fold(row_delta % tab_size, |counter: u32, c| {
10076                        if c == '\t' {
10077                            0
10078                        } else {
10079                            (counter + 1) % tab_size
10080                        }
10081                    });
10082
10083                let chars_to_next_tab_stop = tab_size - indent_remainder;
10084                IndentSize::spaces(chars_to_next_tab_stop)
10085            };
10086            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10087            selection.end = selection.start;
10088            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10089            row_delta += tab_size.len;
10090        }
10091
10092        self.transact(window, cx, |this, window, cx| {
10093            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10094            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10095            this.refresh_edit_prediction(true, false, window, cx);
10096        });
10097    }
10098
10099    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10100        if self.read_only(cx) {
10101            return;
10102        }
10103        if self.mode.is_single_line() {
10104            cx.propagate();
10105            return;
10106        }
10107
10108        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10109        let mut selections = self.selections.all::<Point>(cx);
10110        let mut prev_edited_row = 0;
10111        let mut row_delta = 0;
10112        let mut edits = Vec::new();
10113        let buffer = self.buffer.read(cx);
10114        let snapshot = buffer.snapshot(cx);
10115        for selection in &mut selections {
10116            if selection.start.row != prev_edited_row {
10117                row_delta = 0;
10118            }
10119            prev_edited_row = selection.end.row;
10120
10121            row_delta =
10122                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10123        }
10124
10125        self.transact(window, cx, |this, window, cx| {
10126            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10127            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10128        });
10129    }
10130
10131    fn indent_selection(
10132        buffer: &MultiBuffer,
10133        snapshot: &MultiBufferSnapshot,
10134        selection: &mut Selection<Point>,
10135        edits: &mut Vec<(Range<Point>, String)>,
10136        delta_for_start_row: u32,
10137        cx: &App,
10138    ) -> u32 {
10139        let settings = buffer.language_settings_at(selection.start, cx);
10140        let tab_size = settings.tab_size.get();
10141        let indent_kind = if settings.hard_tabs {
10142            IndentKind::Tab
10143        } else {
10144            IndentKind::Space
10145        };
10146        let mut start_row = selection.start.row;
10147        let mut end_row = selection.end.row + 1;
10148
10149        // If a selection ends at the beginning of a line, don't indent
10150        // that last line.
10151        if selection.end.column == 0 && selection.end.row > selection.start.row {
10152            end_row -= 1;
10153        }
10154
10155        // Avoid re-indenting a row that has already been indented by a
10156        // previous selection, but still update this selection's column
10157        // to reflect that indentation.
10158        if delta_for_start_row > 0 {
10159            start_row += 1;
10160            selection.start.column += delta_for_start_row;
10161            if selection.end.row == selection.start.row {
10162                selection.end.column += delta_for_start_row;
10163            }
10164        }
10165
10166        let mut delta_for_end_row = 0;
10167        let has_multiple_rows = start_row + 1 != end_row;
10168        for row in start_row..end_row {
10169            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10170            let indent_delta = match (current_indent.kind, indent_kind) {
10171                (IndentKind::Space, IndentKind::Space) => {
10172                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10173                    IndentSize::spaces(columns_to_next_tab_stop)
10174                }
10175                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10176                (_, IndentKind::Tab) => IndentSize::tab(),
10177            };
10178
10179            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10180                0
10181            } else {
10182                selection.start.column
10183            };
10184            let row_start = Point::new(row, start);
10185            edits.push((
10186                row_start..row_start,
10187                indent_delta.chars().collect::<String>(),
10188            ));
10189
10190            // Update this selection's endpoints to reflect the indentation.
10191            if row == selection.start.row {
10192                selection.start.column += indent_delta.len;
10193            }
10194            if row == selection.end.row {
10195                selection.end.column += indent_delta.len;
10196                delta_for_end_row = indent_delta.len;
10197            }
10198        }
10199
10200        if selection.start.row == selection.end.row {
10201            delta_for_start_row + delta_for_end_row
10202        } else {
10203            delta_for_end_row
10204        }
10205    }
10206
10207    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10208        if self.read_only(cx) {
10209            return;
10210        }
10211        if self.mode.is_single_line() {
10212            cx.propagate();
10213            return;
10214        }
10215
10216        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10217        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10218        let selections = self.selections.all::<Point>(cx);
10219        let mut deletion_ranges = Vec::new();
10220        let mut last_outdent = None;
10221        {
10222            let buffer = self.buffer.read(cx);
10223            let snapshot = buffer.snapshot(cx);
10224            for selection in &selections {
10225                let settings = buffer.language_settings_at(selection.start, cx);
10226                let tab_size = settings.tab_size.get();
10227                let mut rows = selection.spanned_rows(false, &display_map);
10228
10229                // Avoid re-outdenting a row that has already been outdented by a
10230                // previous selection.
10231                if let Some(last_row) = last_outdent
10232                    && last_row == rows.start
10233                {
10234                    rows.start = rows.start.next_row();
10235                }
10236                let has_multiple_rows = rows.len() > 1;
10237                for row in rows.iter_rows() {
10238                    let indent_size = snapshot.indent_size_for_line(row);
10239                    if indent_size.len > 0 {
10240                        let deletion_len = match indent_size.kind {
10241                            IndentKind::Space => {
10242                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10243                                if columns_to_prev_tab_stop == 0 {
10244                                    tab_size
10245                                } else {
10246                                    columns_to_prev_tab_stop
10247                                }
10248                            }
10249                            IndentKind::Tab => 1,
10250                        };
10251                        let start = if has_multiple_rows
10252                            || deletion_len > selection.start.column
10253                            || indent_size.len < selection.start.column
10254                        {
10255                            0
10256                        } else {
10257                            selection.start.column - deletion_len
10258                        };
10259                        deletion_ranges.push(
10260                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10261                        );
10262                        last_outdent = Some(row);
10263                    }
10264                }
10265            }
10266        }
10267
10268        self.transact(window, cx, |this, window, cx| {
10269            this.buffer.update(cx, |buffer, cx| {
10270                let empty_str: Arc<str> = Arc::default();
10271                buffer.edit(
10272                    deletion_ranges
10273                        .into_iter()
10274                        .map(|range| (range, empty_str.clone())),
10275                    None,
10276                    cx,
10277                );
10278            });
10279            let selections = this.selections.all::<usize>(cx);
10280            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10281        });
10282    }
10283
10284    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10285        if self.read_only(cx) {
10286            return;
10287        }
10288        if self.mode.is_single_line() {
10289            cx.propagate();
10290            return;
10291        }
10292
10293        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10294        let selections = self
10295            .selections
10296            .all::<usize>(cx)
10297            .into_iter()
10298            .map(|s| s.range());
10299
10300        self.transact(window, cx, |this, window, cx| {
10301            this.buffer.update(cx, |buffer, cx| {
10302                buffer.autoindent_ranges(selections, cx);
10303            });
10304            let selections = this.selections.all::<usize>(cx);
10305            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10306        });
10307    }
10308
10309    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10311        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10312        let selections = self.selections.all::<Point>(cx);
10313
10314        let mut new_cursors = Vec::new();
10315        let mut edit_ranges = Vec::new();
10316        let mut selections = selections.iter().peekable();
10317        while let Some(selection) = selections.next() {
10318            let mut rows = selection.spanned_rows(false, &display_map);
10319            let goal_display_column = selection.head().to_display_point(&display_map).column();
10320
10321            // Accumulate contiguous regions of rows that we want to delete.
10322            while let Some(next_selection) = selections.peek() {
10323                let next_rows = next_selection.spanned_rows(false, &display_map);
10324                if next_rows.start <= rows.end {
10325                    rows.end = next_rows.end;
10326                    selections.next().unwrap();
10327                } else {
10328                    break;
10329                }
10330            }
10331
10332            let buffer = &display_map.buffer_snapshot;
10333            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10334            let edit_end;
10335            let cursor_buffer_row;
10336            if buffer.max_point().row >= rows.end.0 {
10337                // If there's a line after the range, delete the \n from the end of the row range
10338                // and position the cursor on the next line.
10339                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10340                cursor_buffer_row = rows.end;
10341            } else {
10342                // If there isn't a line after the range, delete the \n from the line before the
10343                // start of the row range and position the cursor there.
10344                edit_start = edit_start.saturating_sub(1);
10345                edit_end = buffer.len();
10346                cursor_buffer_row = rows.start.previous_row();
10347            }
10348
10349            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10350            *cursor.column_mut() =
10351                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10352
10353            new_cursors.push((
10354                selection.id,
10355                buffer.anchor_after(cursor.to_point(&display_map)),
10356            ));
10357            edit_ranges.push(edit_start..edit_end);
10358        }
10359
10360        self.transact(window, cx, |this, window, cx| {
10361            let buffer = this.buffer.update(cx, |buffer, cx| {
10362                let empty_str: Arc<str> = Arc::default();
10363                buffer.edit(
10364                    edit_ranges
10365                        .into_iter()
10366                        .map(|range| (range, empty_str.clone())),
10367                    None,
10368                    cx,
10369                );
10370                buffer.snapshot(cx)
10371            });
10372            let new_selections = new_cursors
10373                .into_iter()
10374                .map(|(id, cursor)| {
10375                    let cursor = cursor.to_point(&buffer);
10376                    Selection {
10377                        id,
10378                        start: cursor,
10379                        end: cursor,
10380                        reversed: false,
10381                        goal: SelectionGoal::None,
10382                    }
10383                })
10384                .collect();
10385
10386            this.change_selections(Default::default(), window, cx, |s| {
10387                s.select(new_selections);
10388            });
10389        });
10390    }
10391
10392    pub fn join_lines_impl(
10393        &mut self,
10394        insert_whitespace: bool,
10395        window: &mut Window,
10396        cx: &mut Context<Self>,
10397    ) {
10398        if self.read_only(cx) {
10399            return;
10400        }
10401        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10402        for selection in self.selections.all::<Point>(cx) {
10403            let start = MultiBufferRow(selection.start.row);
10404            // Treat single line selections as if they include the next line. Otherwise this action
10405            // would do nothing for single line selections individual cursors.
10406            let end = if selection.start.row == selection.end.row {
10407                MultiBufferRow(selection.start.row + 1)
10408            } else {
10409                MultiBufferRow(selection.end.row)
10410            };
10411
10412            if let Some(last_row_range) = row_ranges.last_mut()
10413                && start <= last_row_range.end
10414            {
10415                last_row_range.end = end;
10416                continue;
10417            }
10418            row_ranges.push(start..end);
10419        }
10420
10421        let snapshot = self.buffer.read(cx).snapshot(cx);
10422        let mut cursor_positions = Vec::new();
10423        for row_range in &row_ranges {
10424            let anchor = snapshot.anchor_before(Point::new(
10425                row_range.end.previous_row().0,
10426                snapshot.line_len(row_range.end.previous_row()),
10427            ));
10428            cursor_positions.push(anchor..anchor);
10429        }
10430
10431        self.transact(window, cx, |this, window, cx| {
10432            for row_range in row_ranges.into_iter().rev() {
10433                for row in row_range.iter_rows().rev() {
10434                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10435                    let next_line_row = row.next_row();
10436                    let indent = snapshot.indent_size_for_line(next_line_row);
10437                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10438
10439                    let replace =
10440                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10441                            " "
10442                        } else {
10443                            ""
10444                        };
10445
10446                    this.buffer.update(cx, |buffer, cx| {
10447                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10448                    });
10449                }
10450            }
10451
10452            this.change_selections(Default::default(), window, cx, |s| {
10453                s.select_anchor_ranges(cursor_positions)
10454            });
10455        });
10456    }
10457
10458    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10460        self.join_lines_impl(true, window, cx);
10461    }
10462
10463    pub fn sort_lines_case_sensitive(
10464        &mut self,
10465        _: &SortLinesCaseSensitive,
10466        window: &mut Window,
10467        cx: &mut Context<Self>,
10468    ) {
10469        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10470    }
10471
10472    pub fn sort_lines_by_length(
10473        &mut self,
10474        _: &SortLinesByLength,
10475        window: &mut Window,
10476        cx: &mut Context<Self>,
10477    ) {
10478        self.manipulate_immutable_lines(window, cx, |lines| {
10479            lines.sort_by_key(|&line| line.chars().count())
10480        })
10481    }
10482
10483    pub fn sort_lines_case_insensitive(
10484        &mut self,
10485        _: &SortLinesCaseInsensitive,
10486        window: &mut Window,
10487        cx: &mut Context<Self>,
10488    ) {
10489        self.manipulate_immutable_lines(window, cx, |lines| {
10490            lines.sort_by_key(|line| line.to_lowercase())
10491        })
10492    }
10493
10494    pub fn unique_lines_case_insensitive(
10495        &mut self,
10496        _: &UniqueLinesCaseInsensitive,
10497        window: &mut Window,
10498        cx: &mut Context<Self>,
10499    ) {
10500        self.manipulate_immutable_lines(window, cx, |lines| {
10501            let mut seen = HashSet::default();
10502            lines.retain(|line| seen.insert(line.to_lowercase()));
10503        })
10504    }
10505
10506    pub fn unique_lines_case_sensitive(
10507        &mut self,
10508        _: &UniqueLinesCaseSensitive,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.manipulate_immutable_lines(window, cx, |lines| {
10513            let mut seen = HashSet::default();
10514            lines.retain(|line| seen.insert(*line));
10515        })
10516    }
10517
10518    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10519        let snapshot = self.buffer.read(cx).snapshot(cx);
10520        for selection in self.selections.disjoint_anchors().iter() {
10521            if snapshot
10522                .language_at(selection.start)
10523                .and_then(|lang| lang.config().wrap_characters.as_ref())
10524                .is_some()
10525            {
10526                return true;
10527            }
10528        }
10529        false
10530    }
10531
10532    fn wrap_selections_in_tag(
10533        &mut self,
10534        _: &WrapSelectionsInTag,
10535        window: &mut Window,
10536        cx: &mut Context<Self>,
10537    ) {
10538        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10539
10540        let snapshot = self.buffer.read(cx).snapshot(cx);
10541
10542        let mut edits = Vec::new();
10543        let mut boundaries = Vec::new();
10544
10545        for selection in self.selections.all::<Point>(cx).iter() {
10546            let Some(wrap_config) = snapshot
10547                .language_at(selection.start)
10548                .and_then(|lang| lang.config().wrap_characters.clone())
10549            else {
10550                continue;
10551            };
10552
10553            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10554            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10555
10556            let start_before = snapshot.anchor_before(selection.start);
10557            let end_after = snapshot.anchor_after(selection.end);
10558
10559            edits.push((start_before..start_before, open_tag));
10560            edits.push((end_after..end_after, close_tag));
10561
10562            boundaries.push((
10563                start_before,
10564                end_after,
10565                wrap_config.start_prefix.len(),
10566                wrap_config.end_suffix.len(),
10567            ));
10568        }
10569
10570        if edits.is_empty() {
10571            return;
10572        }
10573
10574        self.transact(window, cx, |this, window, cx| {
10575            let buffer = this.buffer.update(cx, |buffer, cx| {
10576                buffer.edit(edits, None, cx);
10577                buffer.snapshot(cx)
10578            });
10579
10580            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10581            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10582                boundaries.into_iter()
10583            {
10584                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10585                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10586                new_selections.push(open_offset..open_offset);
10587                new_selections.push(close_offset..close_offset);
10588            }
10589
10590            this.change_selections(Default::default(), window, cx, |s| {
10591                s.select_ranges(new_selections);
10592            });
10593
10594            this.request_autoscroll(Autoscroll::fit(), cx);
10595        });
10596    }
10597
10598    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10599        let Some(project) = self.project.clone() else {
10600            return;
10601        };
10602        self.reload(project, window, cx)
10603            .detach_and_notify_err(window, cx);
10604    }
10605
10606    pub fn restore_file(
10607        &mut self,
10608        _: &::git::RestoreFile,
10609        window: &mut Window,
10610        cx: &mut Context<Self>,
10611    ) {
10612        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10613        let mut buffer_ids = HashSet::default();
10614        let snapshot = self.buffer().read(cx).snapshot(cx);
10615        for selection in self.selections.all::<usize>(cx) {
10616            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10617        }
10618
10619        let buffer = self.buffer().read(cx);
10620        let ranges = buffer_ids
10621            .into_iter()
10622            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10623            .collect::<Vec<_>>();
10624
10625        self.restore_hunks_in_ranges(ranges, window, cx);
10626    }
10627
10628    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10630        let selections = self
10631            .selections
10632            .all(cx)
10633            .into_iter()
10634            .map(|s| s.range())
10635            .collect();
10636        self.restore_hunks_in_ranges(selections, window, cx);
10637    }
10638
10639    pub fn restore_hunks_in_ranges(
10640        &mut self,
10641        ranges: Vec<Range<Point>>,
10642        window: &mut Window,
10643        cx: &mut Context<Editor>,
10644    ) {
10645        let mut revert_changes = HashMap::default();
10646        let chunk_by = self
10647            .snapshot(window, cx)
10648            .hunks_for_ranges(ranges)
10649            .into_iter()
10650            .chunk_by(|hunk| hunk.buffer_id);
10651        for (buffer_id, hunks) in &chunk_by {
10652            let hunks = hunks.collect::<Vec<_>>();
10653            for hunk in &hunks {
10654                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10655            }
10656            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10657        }
10658        drop(chunk_by);
10659        if !revert_changes.is_empty() {
10660            self.transact(window, cx, |editor, window, cx| {
10661                editor.restore(revert_changes, window, cx);
10662            });
10663        }
10664    }
10665
10666    pub fn open_active_item_in_terminal(
10667        &mut self,
10668        _: &OpenInTerminal,
10669        window: &mut Window,
10670        cx: &mut Context<Self>,
10671    ) {
10672        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10673            let project_path = buffer.read(cx).project_path(cx)?;
10674            let project = self.project()?.read(cx);
10675            let entry = project.entry_for_path(&project_path, cx)?;
10676            let parent = match &entry.canonical_path {
10677                Some(canonical_path) => canonical_path.to_path_buf(),
10678                None => project.absolute_path(&project_path, cx)?,
10679            }
10680            .parent()?
10681            .to_path_buf();
10682            Some(parent)
10683        }) {
10684            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10685        }
10686    }
10687
10688    fn set_breakpoint_context_menu(
10689        &mut self,
10690        display_row: DisplayRow,
10691        position: Option<Anchor>,
10692        clicked_point: gpui::Point<Pixels>,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) {
10696        let source = self
10697            .buffer
10698            .read(cx)
10699            .snapshot(cx)
10700            .anchor_before(Point::new(display_row.0, 0u32));
10701
10702        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10703
10704        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10705            self,
10706            source,
10707            clicked_point,
10708            context_menu,
10709            window,
10710            cx,
10711        );
10712    }
10713
10714    fn add_edit_breakpoint_block(
10715        &mut self,
10716        anchor: Anchor,
10717        breakpoint: &Breakpoint,
10718        edit_action: BreakpointPromptEditAction,
10719        window: &mut Window,
10720        cx: &mut Context<Self>,
10721    ) {
10722        let weak_editor = cx.weak_entity();
10723        let bp_prompt = cx.new(|cx| {
10724            BreakpointPromptEditor::new(
10725                weak_editor,
10726                anchor,
10727                breakpoint.clone(),
10728                edit_action,
10729                window,
10730                cx,
10731            )
10732        });
10733
10734        let height = bp_prompt.update(cx, |this, cx| {
10735            this.prompt
10736                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10737        });
10738        let cloned_prompt = bp_prompt.clone();
10739        let blocks = vec![BlockProperties {
10740            style: BlockStyle::Sticky,
10741            placement: BlockPlacement::Above(anchor),
10742            height: Some(height),
10743            render: Arc::new(move |cx| {
10744                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10745                cloned_prompt.clone().into_any_element()
10746            }),
10747            priority: 0,
10748        }];
10749
10750        let focus_handle = bp_prompt.focus_handle(cx);
10751        window.focus(&focus_handle);
10752
10753        let block_ids = self.insert_blocks(blocks, None, cx);
10754        bp_prompt.update(cx, |prompt, _| {
10755            prompt.add_block_ids(block_ids);
10756        });
10757    }
10758
10759    pub(crate) fn breakpoint_at_row(
10760        &self,
10761        row: u32,
10762        window: &mut Window,
10763        cx: &mut Context<Self>,
10764    ) -> Option<(Anchor, Breakpoint)> {
10765        let snapshot = self.snapshot(window, cx);
10766        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10767
10768        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10769    }
10770
10771    pub(crate) fn breakpoint_at_anchor(
10772        &self,
10773        breakpoint_position: Anchor,
10774        snapshot: &EditorSnapshot,
10775        cx: &mut Context<Self>,
10776    ) -> Option<(Anchor, Breakpoint)> {
10777        let buffer = self
10778            .buffer
10779            .read(cx)
10780            .buffer_for_anchor(breakpoint_position, cx)?;
10781
10782        let enclosing_excerpt = breakpoint_position.excerpt_id;
10783        let buffer_snapshot = buffer.read(cx).snapshot();
10784
10785        let row = buffer_snapshot
10786            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10787            .row;
10788
10789        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10790        let anchor_end = snapshot
10791            .buffer_snapshot
10792            .anchor_after(Point::new(row, line_len));
10793
10794        self.breakpoint_store
10795            .as_ref()?
10796            .read_with(cx, |breakpoint_store, cx| {
10797                breakpoint_store
10798                    .breakpoints(
10799                        &buffer,
10800                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10801                        &buffer_snapshot,
10802                        cx,
10803                    )
10804                    .next()
10805                    .and_then(|(bp, _)| {
10806                        let breakpoint_row = buffer_snapshot
10807                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10808                            .row;
10809
10810                        if breakpoint_row == row {
10811                            snapshot
10812                                .buffer_snapshot
10813                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10814                                .map(|position| (position, bp.bp.clone()))
10815                        } else {
10816                            None
10817                        }
10818                    })
10819            })
10820    }
10821
10822    pub fn edit_log_breakpoint(
10823        &mut self,
10824        _: &EditLogBreakpoint,
10825        window: &mut Window,
10826        cx: &mut Context<Self>,
10827    ) {
10828        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10829            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10830                message: None,
10831                state: BreakpointState::Enabled,
10832                condition: None,
10833                hit_condition: None,
10834            });
10835
10836            self.add_edit_breakpoint_block(
10837                anchor,
10838                &breakpoint,
10839                BreakpointPromptEditAction::Log,
10840                window,
10841                cx,
10842            );
10843        }
10844    }
10845
10846    fn breakpoints_at_cursors(
10847        &self,
10848        window: &mut Window,
10849        cx: &mut Context<Self>,
10850    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10851        let snapshot = self.snapshot(window, cx);
10852        let cursors = self
10853            .selections
10854            .disjoint_anchors()
10855            .iter()
10856            .map(|selection| {
10857                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10858
10859                let breakpoint_position = self
10860                    .breakpoint_at_row(cursor_position.row, window, cx)
10861                    .map(|bp| bp.0)
10862                    .unwrap_or_else(|| {
10863                        snapshot
10864                            .display_snapshot
10865                            .buffer_snapshot
10866                            .anchor_after(Point::new(cursor_position.row, 0))
10867                    });
10868
10869                let breakpoint = self
10870                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10871                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10872
10873                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10874            })
10875            // 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.
10876            .collect::<HashMap<Anchor, _>>();
10877
10878        cursors.into_iter().collect()
10879    }
10880
10881    pub fn enable_breakpoint(
10882        &mut self,
10883        _: &crate::actions::EnableBreakpoint,
10884        window: &mut Window,
10885        cx: &mut Context<Self>,
10886    ) {
10887        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10888            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10889                continue;
10890            };
10891            self.edit_breakpoint_at_anchor(
10892                anchor,
10893                breakpoint,
10894                BreakpointEditAction::InvertState,
10895                cx,
10896            );
10897        }
10898    }
10899
10900    pub fn disable_breakpoint(
10901        &mut self,
10902        _: &crate::actions::DisableBreakpoint,
10903        window: &mut Window,
10904        cx: &mut Context<Self>,
10905    ) {
10906        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10907            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10908                continue;
10909            };
10910            self.edit_breakpoint_at_anchor(
10911                anchor,
10912                breakpoint,
10913                BreakpointEditAction::InvertState,
10914                cx,
10915            );
10916        }
10917    }
10918
10919    pub fn toggle_breakpoint(
10920        &mut self,
10921        _: &crate::actions::ToggleBreakpoint,
10922        window: &mut Window,
10923        cx: &mut Context<Self>,
10924    ) {
10925        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10926            if let Some(breakpoint) = breakpoint {
10927                self.edit_breakpoint_at_anchor(
10928                    anchor,
10929                    breakpoint,
10930                    BreakpointEditAction::Toggle,
10931                    cx,
10932                );
10933            } else {
10934                self.edit_breakpoint_at_anchor(
10935                    anchor,
10936                    Breakpoint::new_standard(),
10937                    BreakpointEditAction::Toggle,
10938                    cx,
10939                );
10940            }
10941        }
10942    }
10943
10944    pub fn edit_breakpoint_at_anchor(
10945        &mut self,
10946        breakpoint_position: Anchor,
10947        breakpoint: Breakpoint,
10948        edit_action: BreakpointEditAction,
10949        cx: &mut Context<Self>,
10950    ) {
10951        let Some(breakpoint_store) = &self.breakpoint_store else {
10952            return;
10953        };
10954
10955        let Some(buffer) = self
10956            .buffer
10957            .read(cx)
10958            .buffer_for_anchor(breakpoint_position, cx)
10959        else {
10960            return;
10961        };
10962
10963        breakpoint_store.update(cx, |breakpoint_store, cx| {
10964            breakpoint_store.toggle_breakpoint(
10965                buffer,
10966                BreakpointWithPosition {
10967                    position: breakpoint_position.text_anchor,
10968                    bp: breakpoint,
10969                },
10970                edit_action,
10971                cx,
10972            );
10973        });
10974
10975        cx.notify();
10976    }
10977
10978    #[cfg(any(test, feature = "test-support"))]
10979    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10980        self.breakpoint_store.clone()
10981    }
10982
10983    pub fn prepare_restore_change(
10984        &self,
10985        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10986        hunk: &MultiBufferDiffHunk,
10987        cx: &mut App,
10988    ) -> Option<()> {
10989        if hunk.is_created_file() {
10990            return None;
10991        }
10992        let buffer = self.buffer.read(cx);
10993        let diff = buffer.diff_for(hunk.buffer_id)?;
10994        let buffer = buffer.buffer(hunk.buffer_id)?;
10995        let buffer = buffer.read(cx);
10996        let original_text = diff
10997            .read(cx)
10998            .base_text()
10999            .as_rope()
11000            .slice(hunk.diff_base_byte_range.clone());
11001        let buffer_snapshot = buffer.snapshot();
11002        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11003        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11004            probe
11005                .0
11006                .start
11007                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11008                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11009        }) {
11010            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11011            Some(())
11012        } else {
11013            None
11014        }
11015    }
11016
11017    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11018        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11019    }
11020
11021    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11022        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11023    }
11024
11025    fn manipulate_lines<M>(
11026        &mut self,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029        mut manipulate: M,
11030    ) where
11031        M: FnMut(&str) -> LineManipulationResult,
11032    {
11033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11034
11035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11036        let buffer = self.buffer.read(cx).snapshot(cx);
11037
11038        let mut edits = Vec::new();
11039
11040        let selections = self.selections.all::<Point>(cx);
11041        let mut selections = selections.iter().peekable();
11042        let mut contiguous_row_selections = Vec::new();
11043        let mut new_selections = Vec::new();
11044        let mut added_lines = 0;
11045        let mut removed_lines = 0;
11046
11047        while let Some(selection) = selections.next() {
11048            let (start_row, end_row) = consume_contiguous_rows(
11049                &mut contiguous_row_selections,
11050                selection,
11051                &display_map,
11052                &mut selections,
11053            );
11054
11055            let start_point = Point::new(start_row.0, 0);
11056            let end_point = Point::new(
11057                end_row.previous_row().0,
11058                buffer.line_len(end_row.previous_row()),
11059            );
11060            let text = buffer
11061                .text_for_range(start_point..end_point)
11062                .collect::<String>();
11063
11064            let LineManipulationResult {
11065                new_text,
11066                line_count_before,
11067                line_count_after,
11068            } = manipulate(&text);
11069
11070            edits.push((start_point..end_point, new_text));
11071
11072            // Selections must change based on added and removed line count
11073            let start_row =
11074                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11075            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11076            new_selections.push(Selection {
11077                id: selection.id,
11078                start: start_row,
11079                end: end_row,
11080                goal: SelectionGoal::None,
11081                reversed: selection.reversed,
11082            });
11083
11084            if line_count_after > line_count_before {
11085                added_lines += line_count_after - line_count_before;
11086            } else if line_count_before > line_count_after {
11087                removed_lines += line_count_before - line_count_after;
11088            }
11089        }
11090
11091        self.transact(window, cx, |this, window, cx| {
11092            let buffer = this.buffer.update(cx, |buffer, cx| {
11093                buffer.edit(edits, None, cx);
11094                buffer.snapshot(cx)
11095            });
11096
11097            // Recalculate offsets on newly edited buffer
11098            let new_selections = new_selections
11099                .iter()
11100                .map(|s| {
11101                    let start_point = Point::new(s.start.0, 0);
11102                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11103                    Selection {
11104                        id: s.id,
11105                        start: buffer.point_to_offset(start_point),
11106                        end: buffer.point_to_offset(end_point),
11107                        goal: s.goal,
11108                        reversed: s.reversed,
11109                    }
11110                })
11111                .collect();
11112
11113            this.change_selections(Default::default(), window, cx, |s| {
11114                s.select(new_selections);
11115            });
11116
11117            this.request_autoscroll(Autoscroll::fit(), cx);
11118        });
11119    }
11120
11121    fn manipulate_immutable_lines<Fn>(
11122        &mut self,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125        mut callback: Fn,
11126    ) where
11127        Fn: FnMut(&mut Vec<&str>),
11128    {
11129        self.manipulate_lines(window, cx, |text| {
11130            let mut lines: Vec<&str> = text.split('\n').collect();
11131            let line_count_before = lines.len();
11132
11133            callback(&mut lines);
11134
11135            LineManipulationResult {
11136                new_text: lines.join("\n"),
11137                line_count_before,
11138                line_count_after: lines.len(),
11139            }
11140        });
11141    }
11142
11143    fn manipulate_mutable_lines<Fn>(
11144        &mut self,
11145        window: &mut Window,
11146        cx: &mut Context<Self>,
11147        mut callback: Fn,
11148    ) where
11149        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11150    {
11151        self.manipulate_lines(window, cx, |text| {
11152            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11153            let line_count_before = lines.len();
11154
11155            callback(&mut lines);
11156
11157            LineManipulationResult {
11158                new_text: lines.join("\n"),
11159                line_count_before,
11160                line_count_after: lines.len(),
11161            }
11162        });
11163    }
11164
11165    pub fn convert_indentation_to_spaces(
11166        &mut self,
11167        _: &ConvertIndentationToSpaces,
11168        window: &mut Window,
11169        cx: &mut Context<Self>,
11170    ) {
11171        let settings = self.buffer.read(cx).language_settings(cx);
11172        let tab_size = settings.tab_size.get() as usize;
11173
11174        self.manipulate_mutable_lines(window, cx, |lines| {
11175            // Allocates a reasonably sized scratch buffer once for the whole loop
11176            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11177            // Avoids recomputing spaces that could be inserted many times
11178            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11179                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11180                .collect();
11181
11182            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11183                let mut chars = line.as_ref().chars();
11184                let mut col = 0;
11185                let mut changed = false;
11186
11187                for ch in chars.by_ref() {
11188                    match ch {
11189                        ' ' => {
11190                            reindented_line.push(' ');
11191                            col += 1;
11192                        }
11193                        '\t' => {
11194                            // \t are converted to spaces depending on the current column
11195                            let spaces_len = tab_size - (col % tab_size);
11196                            reindented_line.extend(&space_cache[spaces_len - 1]);
11197                            col += spaces_len;
11198                            changed = true;
11199                        }
11200                        _ => {
11201                            // If we dont append before break, the character is consumed
11202                            reindented_line.push(ch);
11203                            break;
11204                        }
11205                    }
11206                }
11207
11208                if !changed {
11209                    reindented_line.clear();
11210                    continue;
11211                }
11212                // Append the rest of the line and replace old reference with new one
11213                reindented_line.extend(chars);
11214                *line = Cow::Owned(reindented_line.clone());
11215                reindented_line.clear();
11216            }
11217        });
11218    }
11219
11220    pub fn convert_indentation_to_tabs(
11221        &mut self,
11222        _: &ConvertIndentationToTabs,
11223        window: &mut Window,
11224        cx: &mut Context<Self>,
11225    ) {
11226        let settings = self.buffer.read(cx).language_settings(cx);
11227        let tab_size = settings.tab_size.get() as usize;
11228
11229        self.manipulate_mutable_lines(window, cx, |lines| {
11230            // Allocates a reasonably sized buffer once for the whole loop
11231            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11232            // Avoids recomputing spaces that could be inserted many times
11233            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11234                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11235                .collect();
11236
11237            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11238                let mut chars = line.chars();
11239                let mut spaces_count = 0;
11240                let mut first_non_indent_char = None;
11241                let mut changed = false;
11242
11243                for ch in chars.by_ref() {
11244                    match ch {
11245                        ' ' => {
11246                            // Keep track of spaces. Append \t when we reach tab_size
11247                            spaces_count += 1;
11248                            changed = true;
11249                            if spaces_count == tab_size {
11250                                reindented_line.push('\t');
11251                                spaces_count = 0;
11252                            }
11253                        }
11254                        '\t' => {
11255                            reindented_line.push('\t');
11256                            spaces_count = 0;
11257                        }
11258                        _ => {
11259                            // Dont append it yet, we might have remaining spaces
11260                            first_non_indent_char = Some(ch);
11261                            break;
11262                        }
11263                    }
11264                }
11265
11266                if !changed {
11267                    reindented_line.clear();
11268                    continue;
11269                }
11270                // Remaining spaces that didn't make a full tab stop
11271                if spaces_count > 0 {
11272                    reindented_line.extend(&space_cache[spaces_count - 1]);
11273                }
11274                // If we consume an extra character that was not indentation, add it back
11275                if let Some(extra_char) = first_non_indent_char {
11276                    reindented_line.push(extra_char);
11277                }
11278                // Append the rest of the line and replace old reference with new one
11279                reindented_line.extend(chars);
11280                *line = Cow::Owned(reindented_line.clone());
11281                reindented_line.clear();
11282            }
11283        });
11284    }
11285
11286    pub fn convert_to_upper_case(
11287        &mut self,
11288        _: &ConvertToUpperCase,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        self.manipulate_text(window, cx, |text| text.to_uppercase())
11293    }
11294
11295    pub fn convert_to_lower_case(
11296        &mut self,
11297        _: &ConvertToLowerCase,
11298        window: &mut Window,
11299        cx: &mut Context<Self>,
11300    ) {
11301        self.manipulate_text(window, cx, |text| text.to_lowercase())
11302    }
11303
11304    pub fn convert_to_title_case(
11305        &mut self,
11306        _: &ConvertToTitleCase,
11307        window: &mut Window,
11308        cx: &mut Context<Self>,
11309    ) {
11310        self.manipulate_text(window, cx, |text| {
11311            text.split('\n')
11312                .map(|line| line.to_case(Case::Title))
11313                .join("\n")
11314        })
11315    }
11316
11317    pub fn convert_to_snake_case(
11318        &mut self,
11319        _: &ConvertToSnakeCase,
11320        window: &mut Window,
11321        cx: &mut Context<Self>,
11322    ) {
11323        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11324    }
11325
11326    pub fn convert_to_kebab_case(
11327        &mut self,
11328        _: &ConvertToKebabCase,
11329        window: &mut Window,
11330        cx: &mut Context<Self>,
11331    ) {
11332        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11333    }
11334
11335    pub fn convert_to_upper_camel_case(
11336        &mut self,
11337        _: &ConvertToUpperCamelCase,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        self.manipulate_text(window, cx, |text| {
11342            text.split('\n')
11343                .map(|line| line.to_case(Case::UpperCamel))
11344                .join("\n")
11345        })
11346    }
11347
11348    pub fn convert_to_lower_camel_case(
11349        &mut self,
11350        _: &ConvertToLowerCamelCase,
11351        window: &mut Window,
11352        cx: &mut Context<Self>,
11353    ) {
11354        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11355    }
11356
11357    pub fn convert_to_opposite_case(
11358        &mut self,
11359        _: &ConvertToOppositeCase,
11360        window: &mut Window,
11361        cx: &mut Context<Self>,
11362    ) {
11363        self.manipulate_text(window, cx, |text| {
11364            text.chars()
11365                .fold(String::with_capacity(text.len()), |mut t, c| {
11366                    if c.is_uppercase() {
11367                        t.extend(c.to_lowercase());
11368                    } else {
11369                        t.extend(c.to_uppercase());
11370                    }
11371                    t
11372                })
11373        })
11374    }
11375
11376    pub fn convert_to_sentence_case(
11377        &mut self,
11378        _: &ConvertToSentenceCase,
11379        window: &mut Window,
11380        cx: &mut Context<Self>,
11381    ) {
11382        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11383    }
11384
11385    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11386        self.manipulate_text(window, cx, |text| {
11387            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11388            if has_upper_case_characters {
11389                text.to_lowercase()
11390            } else {
11391                text.to_uppercase()
11392            }
11393        })
11394    }
11395
11396    pub fn convert_to_rot13(
11397        &mut self,
11398        _: &ConvertToRot13,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        self.manipulate_text(window, cx, |text| {
11403            text.chars()
11404                .map(|c| match c {
11405                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11406                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11407                    _ => c,
11408                })
11409                .collect()
11410        })
11411    }
11412
11413    pub fn convert_to_rot47(
11414        &mut self,
11415        _: &ConvertToRot47,
11416        window: &mut Window,
11417        cx: &mut Context<Self>,
11418    ) {
11419        self.manipulate_text(window, cx, |text| {
11420            text.chars()
11421                .map(|c| {
11422                    let code_point = c as u32;
11423                    if code_point >= 33 && code_point <= 126 {
11424                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11425                    }
11426                    c
11427                })
11428                .collect()
11429        })
11430    }
11431
11432    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11433    where
11434        Fn: FnMut(&str) -> String,
11435    {
11436        let buffer = self.buffer.read(cx).snapshot(cx);
11437
11438        let mut new_selections = Vec::new();
11439        let mut edits = Vec::new();
11440        let mut selection_adjustment = 0i32;
11441
11442        for selection in self.selections.all_adjusted(cx) {
11443            let selection_is_empty = selection.is_empty();
11444
11445            let (start, end) = if selection_is_empty {
11446                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11447                (word_range.start, word_range.end)
11448            } else {
11449                (
11450                    buffer.point_to_offset(selection.start),
11451                    buffer.point_to_offset(selection.end),
11452                )
11453            };
11454
11455            let text = buffer.text_for_range(start..end).collect::<String>();
11456            let old_length = text.len() as i32;
11457            let text = callback(&text);
11458
11459            new_selections.push(Selection {
11460                start: (start as i32 - selection_adjustment) as usize,
11461                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11462                goal: SelectionGoal::None,
11463                id: selection.id,
11464                reversed: selection.reversed,
11465            });
11466
11467            selection_adjustment += old_length - text.len() as i32;
11468
11469            edits.push((start..end, text));
11470        }
11471
11472        self.transact(window, cx, |this, window, cx| {
11473            this.buffer.update(cx, |buffer, cx| {
11474                buffer.edit(edits, None, cx);
11475            });
11476
11477            this.change_selections(Default::default(), window, cx, |s| {
11478                s.select(new_selections);
11479            });
11480
11481            this.request_autoscroll(Autoscroll::fit(), cx);
11482        });
11483    }
11484
11485    pub fn move_selection_on_drop(
11486        &mut self,
11487        selection: &Selection<Anchor>,
11488        target: DisplayPoint,
11489        is_cut: bool,
11490        window: &mut Window,
11491        cx: &mut Context<Self>,
11492    ) {
11493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11494        let buffer = &display_map.buffer_snapshot;
11495        let mut edits = Vec::new();
11496        let insert_point = display_map
11497            .clip_point(target, Bias::Left)
11498            .to_point(&display_map);
11499        let text = buffer
11500            .text_for_range(selection.start..selection.end)
11501            .collect::<String>();
11502        if is_cut {
11503            edits.push(((selection.start..selection.end), String::new()));
11504        }
11505        let insert_anchor = buffer.anchor_before(insert_point);
11506        edits.push(((insert_anchor..insert_anchor), text));
11507        let last_edit_start = insert_anchor.bias_left(buffer);
11508        let last_edit_end = insert_anchor.bias_right(buffer);
11509        self.transact(window, cx, |this, window, cx| {
11510            this.buffer.update(cx, |buffer, cx| {
11511                buffer.edit(edits, None, cx);
11512            });
11513            this.change_selections(Default::default(), window, cx, |s| {
11514                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11515            });
11516        });
11517    }
11518
11519    pub fn clear_selection_drag_state(&mut self) {
11520        self.selection_drag_state = SelectionDragState::None;
11521    }
11522
11523    pub fn duplicate(
11524        &mut self,
11525        upwards: bool,
11526        whole_lines: bool,
11527        window: &mut Window,
11528        cx: &mut Context<Self>,
11529    ) {
11530        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11531
11532        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11533        let buffer = &display_map.buffer_snapshot;
11534        let selections = self.selections.all::<Point>(cx);
11535
11536        let mut edits = Vec::new();
11537        let mut selections_iter = selections.iter().peekable();
11538        while let Some(selection) = selections_iter.next() {
11539            let mut rows = selection.spanned_rows(false, &display_map);
11540            // duplicate line-wise
11541            if whole_lines || selection.start == selection.end {
11542                // Avoid duplicating the same lines twice.
11543                while let Some(next_selection) = selections_iter.peek() {
11544                    let next_rows = next_selection.spanned_rows(false, &display_map);
11545                    if next_rows.start < rows.end {
11546                        rows.end = next_rows.end;
11547                        selections_iter.next().unwrap();
11548                    } else {
11549                        break;
11550                    }
11551                }
11552
11553                // Copy the text from the selected row region and splice it either at the start
11554                // or end of the region.
11555                let start = Point::new(rows.start.0, 0);
11556                let end = Point::new(
11557                    rows.end.previous_row().0,
11558                    buffer.line_len(rows.end.previous_row()),
11559                );
11560                let text = buffer
11561                    .text_for_range(start..end)
11562                    .chain(Some("\n"))
11563                    .collect::<String>();
11564                let insert_location = if upwards {
11565                    Point::new(rows.end.0, 0)
11566                } else {
11567                    start
11568                };
11569                edits.push((insert_location..insert_location, text));
11570            } else {
11571                // duplicate character-wise
11572                let start = selection.start;
11573                let end = selection.end;
11574                let text = buffer.text_for_range(start..end).collect::<String>();
11575                edits.push((selection.end..selection.end, text));
11576            }
11577        }
11578
11579        self.transact(window, cx, |this, _, cx| {
11580            this.buffer.update(cx, |buffer, cx| {
11581                buffer.edit(edits, None, cx);
11582            });
11583
11584            this.request_autoscroll(Autoscroll::fit(), cx);
11585        });
11586    }
11587
11588    pub fn duplicate_line_up(
11589        &mut self,
11590        _: &DuplicateLineUp,
11591        window: &mut Window,
11592        cx: &mut Context<Self>,
11593    ) {
11594        self.duplicate(true, true, window, cx);
11595    }
11596
11597    pub fn duplicate_line_down(
11598        &mut self,
11599        _: &DuplicateLineDown,
11600        window: &mut Window,
11601        cx: &mut Context<Self>,
11602    ) {
11603        self.duplicate(false, true, window, cx);
11604    }
11605
11606    pub fn duplicate_selection(
11607        &mut self,
11608        _: &DuplicateSelection,
11609        window: &mut Window,
11610        cx: &mut Context<Self>,
11611    ) {
11612        self.duplicate(false, false, window, cx);
11613    }
11614
11615    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11616        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11617        if self.mode.is_single_line() {
11618            cx.propagate();
11619            return;
11620        }
11621
11622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11623        let buffer = self.buffer.read(cx).snapshot(cx);
11624
11625        let mut edits = Vec::new();
11626        let mut unfold_ranges = Vec::new();
11627        let mut refold_creases = Vec::new();
11628
11629        let selections = self.selections.all::<Point>(cx);
11630        let mut selections = selections.iter().peekable();
11631        let mut contiguous_row_selections = Vec::new();
11632        let mut new_selections = Vec::new();
11633
11634        while let Some(selection) = selections.next() {
11635            // Find all the selections that span a contiguous row range
11636            let (start_row, end_row) = consume_contiguous_rows(
11637                &mut contiguous_row_selections,
11638                selection,
11639                &display_map,
11640                &mut selections,
11641            );
11642
11643            // Move the text spanned by the row range to be before the line preceding the row range
11644            if start_row.0 > 0 {
11645                let range_to_move = Point::new(
11646                    start_row.previous_row().0,
11647                    buffer.line_len(start_row.previous_row()),
11648                )
11649                    ..Point::new(
11650                        end_row.previous_row().0,
11651                        buffer.line_len(end_row.previous_row()),
11652                    );
11653                let insertion_point = display_map
11654                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11655                    .0;
11656
11657                // Don't move lines across excerpts
11658                if buffer
11659                    .excerpt_containing(insertion_point..range_to_move.end)
11660                    .is_some()
11661                {
11662                    let text = buffer
11663                        .text_for_range(range_to_move.clone())
11664                        .flat_map(|s| s.chars())
11665                        .skip(1)
11666                        .chain(['\n'])
11667                        .collect::<String>();
11668
11669                    edits.push((
11670                        buffer.anchor_after(range_to_move.start)
11671                            ..buffer.anchor_before(range_to_move.end),
11672                        String::new(),
11673                    ));
11674                    let insertion_anchor = buffer.anchor_after(insertion_point);
11675                    edits.push((insertion_anchor..insertion_anchor, text));
11676
11677                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11678
11679                    // Move selections up
11680                    new_selections.extend(contiguous_row_selections.drain(..).map(
11681                        |mut selection| {
11682                            selection.start.row -= row_delta;
11683                            selection.end.row -= row_delta;
11684                            selection
11685                        },
11686                    ));
11687
11688                    // Move folds up
11689                    unfold_ranges.push(range_to_move.clone());
11690                    for fold in display_map.folds_in_range(
11691                        buffer.anchor_before(range_to_move.start)
11692                            ..buffer.anchor_after(range_to_move.end),
11693                    ) {
11694                        let mut start = fold.range.start.to_point(&buffer);
11695                        let mut end = fold.range.end.to_point(&buffer);
11696                        start.row -= row_delta;
11697                        end.row -= row_delta;
11698                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11699                    }
11700                }
11701            }
11702
11703            // If we didn't move line(s), preserve the existing selections
11704            new_selections.append(&mut contiguous_row_selections);
11705        }
11706
11707        self.transact(window, cx, |this, window, cx| {
11708            this.unfold_ranges(&unfold_ranges, true, true, cx);
11709            this.buffer.update(cx, |buffer, cx| {
11710                for (range, text) in edits {
11711                    buffer.edit([(range, text)], None, cx);
11712                }
11713            });
11714            this.fold_creases(refold_creases, true, window, cx);
11715            this.change_selections(Default::default(), window, cx, |s| {
11716                s.select(new_selections);
11717            })
11718        });
11719    }
11720
11721    pub fn move_line_down(
11722        &mut self,
11723        _: &MoveLineDown,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11728        if self.mode.is_single_line() {
11729            cx.propagate();
11730            return;
11731        }
11732
11733        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11734        let buffer = self.buffer.read(cx).snapshot(cx);
11735
11736        let mut edits = Vec::new();
11737        let mut unfold_ranges = Vec::new();
11738        let mut refold_creases = Vec::new();
11739
11740        let selections = self.selections.all::<Point>(cx);
11741        let mut selections = selections.iter().peekable();
11742        let mut contiguous_row_selections = Vec::new();
11743        let mut new_selections = Vec::new();
11744
11745        while let Some(selection) = selections.next() {
11746            // Find all the selections that span a contiguous row range
11747            let (start_row, end_row) = consume_contiguous_rows(
11748                &mut contiguous_row_selections,
11749                selection,
11750                &display_map,
11751                &mut selections,
11752            );
11753
11754            // Move the text spanned by the row range to be after the last line of the row range
11755            if end_row.0 <= buffer.max_point().row {
11756                let range_to_move =
11757                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11758                let insertion_point = display_map
11759                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11760                    .0;
11761
11762                // Don't move lines across excerpt boundaries
11763                if buffer
11764                    .excerpt_containing(range_to_move.start..insertion_point)
11765                    .is_some()
11766                {
11767                    let mut text = String::from("\n");
11768                    text.extend(buffer.text_for_range(range_to_move.clone()));
11769                    text.pop(); // Drop trailing newline
11770                    edits.push((
11771                        buffer.anchor_after(range_to_move.start)
11772                            ..buffer.anchor_before(range_to_move.end),
11773                        String::new(),
11774                    ));
11775                    let insertion_anchor = buffer.anchor_after(insertion_point);
11776                    edits.push((insertion_anchor..insertion_anchor, text));
11777
11778                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11779
11780                    // Move selections down
11781                    new_selections.extend(contiguous_row_selections.drain(..).map(
11782                        |mut selection| {
11783                            selection.start.row += row_delta;
11784                            selection.end.row += row_delta;
11785                            selection
11786                        },
11787                    ));
11788
11789                    // Move folds down
11790                    unfold_ranges.push(range_to_move.clone());
11791                    for fold in display_map.folds_in_range(
11792                        buffer.anchor_before(range_to_move.start)
11793                            ..buffer.anchor_after(range_to_move.end),
11794                    ) {
11795                        let mut start = fold.range.start.to_point(&buffer);
11796                        let mut end = fold.range.end.to_point(&buffer);
11797                        start.row += row_delta;
11798                        end.row += row_delta;
11799                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11800                    }
11801                }
11802            }
11803
11804            // If we didn't move line(s), preserve the existing selections
11805            new_selections.append(&mut contiguous_row_selections);
11806        }
11807
11808        self.transact(window, cx, |this, window, cx| {
11809            this.unfold_ranges(&unfold_ranges, true, true, cx);
11810            this.buffer.update(cx, |buffer, cx| {
11811                for (range, text) in edits {
11812                    buffer.edit([(range, text)], None, cx);
11813                }
11814            });
11815            this.fold_creases(refold_creases, true, window, cx);
11816            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11817        });
11818    }
11819
11820    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11822        let text_layout_details = &self.text_layout_details(window);
11823        self.transact(window, cx, |this, window, cx| {
11824            let edits = this.change_selections(Default::default(), window, cx, |s| {
11825                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11826                s.move_with(|display_map, selection| {
11827                    if !selection.is_empty() {
11828                        return;
11829                    }
11830
11831                    let mut head = selection.head();
11832                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11833                    if head.column() == display_map.line_len(head.row()) {
11834                        transpose_offset = display_map
11835                            .buffer_snapshot
11836                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11837                    }
11838
11839                    if transpose_offset == 0 {
11840                        return;
11841                    }
11842
11843                    *head.column_mut() += 1;
11844                    head = display_map.clip_point(head, Bias::Right);
11845                    let goal = SelectionGoal::HorizontalPosition(
11846                        display_map
11847                            .x_for_display_point(head, text_layout_details)
11848                            .into(),
11849                    );
11850                    selection.collapse_to(head, goal);
11851
11852                    let transpose_start = display_map
11853                        .buffer_snapshot
11854                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11855                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11856                        let transpose_end = display_map
11857                            .buffer_snapshot
11858                            .clip_offset(transpose_offset + 1, Bias::Right);
11859                        if let Some(ch) =
11860                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11861                        {
11862                            edits.push((transpose_start..transpose_offset, String::new()));
11863                            edits.push((transpose_end..transpose_end, ch.to_string()));
11864                        }
11865                    }
11866                });
11867                edits
11868            });
11869            this.buffer
11870                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11871            let selections = this.selections.all::<usize>(cx);
11872            this.change_selections(Default::default(), window, cx, |s| {
11873                s.select(selections);
11874            });
11875        });
11876    }
11877
11878    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11880        if self.mode.is_single_line() {
11881            cx.propagate();
11882            return;
11883        }
11884
11885        self.rewrap_impl(RewrapOptions::default(), cx)
11886    }
11887
11888    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11889        let buffer = self.buffer.read(cx).snapshot(cx);
11890        let selections = self.selections.all::<Point>(cx);
11891
11892        #[derive(Clone, Debug, PartialEq)]
11893        enum CommentFormat {
11894            /// single line comment, with prefix for line
11895            Line(String),
11896            /// single line within a block comment, with prefix for line
11897            BlockLine(String),
11898            /// a single line of a block comment that includes the initial delimiter
11899            BlockCommentWithStart(BlockCommentConfig),
11900            /// a single line of a block comment that includes the ending delimiter
11901            BlockCommentWithEnd(BlockCommentConfig),
11902        }
11903
11904        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11905        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11906            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11907                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11908                .peekable();
11909
11910            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11911                row
11912            } else {
11913                return Vec::new();
11914            };
11915
11916            let language_settings = buffer.language_settings_at(selection.head(), cx);
11917            let language_scope = buffer.language_scope_at(selection.head());
11918
11919            let indent_and_prefix_for_row =
11920                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11921                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11922                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11923                        &language_scope
11924                    {
11925                        let indent_end = Point::new(row, indent.len);
11926                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11927                        let line_text_after_indent = buffer
11928                            .text_for_range(indent_end..line_end)
11929                            .collect::<String>();
11930
11931                        let is_within_comment_override = buffer
11932                            .language_scope_at(indent_end)
11933                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11934                        let comment_delimiters = if is_within_comment_override {
11935                            // we are within a comment syntax node, but we don't
11936                            // yet know what kind of comment: block, doc or line
11937                            match (
11938                                language_scope.documentation_comment(),
11939                                language_scope.block_comment(),
11940                            ) {
11941                                (Some(config), _) | (_, Some(config))
11942                                    if buffer.contains_str_at(indent_end, &config.start) =>
11943                                {
11944                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11945                                }
11946                                (Some(config), _) | (_, Some(config))
11947                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11948                                {
11949                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11950                                }
11951                                (Some(config), _) | (_, Some(config))
11952                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11953                                {
11954                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11955                                }
11956                                (_, _) => language_scope
11957                                    .line_comment_prefixes()
11958                                    .iter()
11959                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11960                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11961                            }
11962                        } else {
11963                            // we not in an overridden comment node, but we may
11964                            // be within a non-overridden line comment node
11965                            language_scope
11966                                .line_comment_prefixes()
11967                                .iter()
11968                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11969                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11970                        };
11971
11972                        let rewrap_prefix = language_scope
11973                            .rewrap_prefixes()
11974                            .iter()
11975                            .find_map(|prefix_regex| {
11976                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11977                                    if mat.start() == 0 {
11978                                        Some(mat.as_str().to_string())
11979                                    } else {
11980                                        None
11981                                    }
11982                                })
11983                            })
11984                            .flatten();
11985                        (comment_delimiters, rewrap_prefix)
11986                    } else {
11987                        (None, None)
11988                    };
11989                    (indent, comment_prefix, rewrap_prefix)
11990                };
11991
11992            let mut ranges = Vec::new();
11993            let from_empty_selection = selection.is_empty();
11994
11995            let mut current_range_start = first_row;
11996            let mut prev_row = first_row;
11997            let (
11998                mut current_range_indent,
11999                mut current_range_comment_delimiters,
12000                mut current_range_rewrap_prefix,
12001            ) = indent_and_prefix_for_row(first_row);
12002
12003            for row in non_blank_rows_iter.skip(1) {
12004                let has_paragraph_break = row > prev_row + 1;
12005
12006                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12007                    indent_and_prefix_for_row(row);
12008
12009                let has_indent_change = row_indent != current_range_indent;
12010                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12011
12012                let has_boundary_change = has_comment_change
12013                    || row_rewrap_prefix.is_some()
12014                    || (has_indent_change && current_range_comment_delimiters.is_some());
12015
12016                if has_paragraph_break || has_boundary_change {
12017                    ranges.push((
12018                        language_settings.clone(),
12019                        Point::new(current_range_start, 0)
12020                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12021                        current_range_indent,
12022                        current_range_comment_delimiters.clone(),
12023                        current_range_rewrap_prefix.clone(),
12024                        from_empty_selection,
12025                    ));
12026                    current_range_start = row;
12027                    current_range_indent = row_indent;
12028                    current_range_comment_delimiters = row_comment_delimiters;
12029                    current_range_rewrap_prefix = row_rewrap_prefix;
12030                }
12031                prev_row = row;
12032            }
12033
12034            ranges.push((
12035                language_settings.clone(),
12036                Point::new(current_range_start, 0)
12037                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12038                current_range_indent,
12039                current_range_comment_delimiters,
12040                current_range_rewrap_prefix,
12041                from_empty_selection,
12042            ));
12043
12044            ranges
12045        });
12046
12047        let mut edits = Vec::new();
12048        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12049
12050        for (
12051            language_settings,
12052            wrap_range,
12053            mut indent_size,
12054            comment_prefix,
12055            rewrap_prefix,
12056            from_empty_selection,
12057        ) in wrap_ranges
12058        {
12059            let mut start_row = wrap_range.start.row;
12060            let mut end_row = wrap_range.end.row;
12061
12062            // Skip selections that overlap with a range that has already been rewrapped.
12063            let selection_range = start_row..end_row;
12064            if rewrapped_row_ranges
12065                .iter()
12066                .any(|range| range.overlaps(&selection_range))
12067            {
12068                continue;
12069            }
12070
12071            let tab_size = language_settings.tab_size;
12072
12073            let (line_prefix, inside_comment) = match &comment_prefix {
12074                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12075                    (Some(prefix.as_str()), true)
12076                }
12077                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12078                    (Some(prefix.as_ref()), true)
12079                }
12080                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12081                    start: _,
12082                    end: _,
12083                    prefix,
12084                    tab_size,
12085                })) => {
12086                    indent_size.len += tab_size;
12087                    (Some(prefix.as_ref()), true)
12088                }
12089                None => (None, false),
12090            };
12091            let indent_prefix = indent_size.chars().collect::<String>();
12092            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12093
12094            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12095                RewrapBehavior::InComments => inside_comment,
12096                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12097                RewrapBehavior::Anywhere => true,
12098            };
12099
12100            let should_rewrap = options.override_language_settings
12101                || allow_rewrap_based_on_language
12102                || self.hard_wrap.is_some();
12103            if !should_rewrap {
12104                continue;
12105            }
12106
12107            if from_empty_selection {
12108                'expand_upwards: while start_row > 0 {
12109                    let prev_row = start_row - 1;
12110                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12111                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12112                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12113                    {
12114                        start_row = prev_row;
12115                    } else {
12116                        break 'expand_upwards;
12117                    }
12118                }
12119
12120                'expand_downwards: while end_row < buffer.max_point().row {
12121                    let next_row = end_row + 1;
12122                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12123                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12124                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12125                    {
12126                        end_row = next_row;
12127                    } else {
12128                        break 'expand_downwards;
12129                    }
12130                }
12131            }
12132
12133            let start = Point::new(start_row, 0);
12134            let start_offset = start.to_offset(&buffer);
12135            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12136            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12137            let mut first_line_delimiter = None;
12138            let mut last_line_delimiter = None;
12139            let Some(lines_without_prefixes) = selection_text
12140                .lines()
12141                .enumerate()
12142                .map(|(ix, line)| {
12143                    let line_trimmed = line.trim_start();
12144                    if rewrap_prefix.is_some() && ix > 0 {
12145                        Ok(line_trimmed)
12146                    } else if let Some(
12147                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12148                            start,
12149                            prefix,
12150                            end,
12151                            tab_size,
12152                        })
12153                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12154                            start,
12155                            prefix,
12156                            end,
12157                            tab_size,
12158                        }),
12159                    ) = &comment_prefix
12160                    {
12161                        let line_trimmed = line_trimmed
12162                            .strip_prefix(start.as_ref())
12163                            .map(|s| {
12164                                let mut indent_size = indent_size;
12165                                indent_size.len -= tab_size;
12166                                let indent_prefix: String = indent_size.chars().collect();
12167                                first_line_delimiter = Some((indent_prefix, start));
12168                                s.trim_start()
12169                            })
12170                            .unwrap_or(line_trimmed);
12171                        let line_trimmed = line_trimmed
12172                            .strip_suffix(end.as_ref())
12173                            .map(|s| {
12174                                last_line_delimiter = Some(end);
12175                                s.trim_end()
12176                            })
12177                            .unwrap_or(line_trimmed);
12178                        let line_trimmed = line_trimmed
12179                            .strip_prefix(prefix.as_ref())
12180                            .unwrap_or(line_trimmed);
12181                        Ok(line_trimmed)
12182                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12183                        line_trimmed.strip_prefix(prefix).with_context(|| {
12184                            format!("line did not start with prefix {prefix:?}: {line:?}")
12185                        })
12186                    } else {
12187                        line_trimmed
12188                            .strip_prefix(&line_prefix.trim_start())
12189                            .with_context(|| {
12190                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12191                            })
12192                    }
12193                })
12194                .collect::<Result<Vec<_>, _>>()
12195                .log_err()
12196            else {
12197                continue;
12198            };
12199
12200            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12201                buffer
12202                    .language_settings_at(Point::new(start_row, 0), cx)
12203                    .preferred_line_length as usize
12204            });
12205
12206            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12207                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12208            } else {
12209                line_prefix.clone()
12210            };
12211
12212            let wrapped_text = {
12213                let mut wrapped_text = wrap_with_prefix(
12214                    line_prefix,
12215                    subsequent_lines_prefix,
12216                    lines_without_prefixes.join("\n"),
12217                    wrap_column,
12218                    tab_size,
12219                    options.preserve_existing_whitespace,
12220                );
12221
12222                if let Some((indent, delimiter)) = first_line_delimiter {
12223                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12224                }
12225                if let Some(last_line) = last_line_delimiter {
12226                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12227                }
12228
12229                wrapped_text
12230            };
12231
12232            // TODO: should always use char-based diff while still supporting cursor behavior that
12233            // matches vim.
12234            let mut diff_options = DiffOptions::default();
12235            if options.override_language_settings {
12236                diff_options.max_word_diff_len = 0;
12237                diff_options.max_word_diff_line_count = 0;
12238            } else {
12239                diff_options.max_word_diff_len = usize::MAX;
12240                diff_options.max_word_diff_line_count = usize::MAX;
12241            }
12242
12243            for (old_range, new_text) in
12244                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12245            {
12246                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12247                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12248                edits.push((edit_start..edit_end, new_text));
12249            }
12250
12251            rewrapped_row_ranges.push(start_row..=end_row);
12252        }
12253
12254        self.buffer
12255            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12256    }
12257
12258    pub fn cut_common(
12259        &mut self,
12260        cut_no_selection_line: bool,
12261        window: &mut Window,
12262        cx: &mut Context<Self>,
12263    ) -> ClipboardItem {
12264        let mut text = String::new();
12265        let buffer = self.buffer.read(cx).snapshot(cx);
12266        let mut selections = self.selections.all::<Point>(cx);
12267        let mut clipboard_selections = Vec::with_capacity(selections.len());
12268        {
12269            let max_point = buffer.max_point();
12270            let mut is_first = true;
12271            for selection in &mut selections {
12272                let is_entire_line =
12273                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12274                if is_entire_line {
12275                    selection.start = Point::new(selection.start.row, 0);
12276                    if !selection.is_empty() && selection.end.column == 0 {
12277                        selection.end = cmp::min(max_point, selection.end);
12278                    } else {
12279                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12280                    }
12281                    selection.goal = SelectionGoal::None;
12282                }
12283                if is_first {
12284                    is_first = false;
12285                } else {
12286                    text += "\n";
12287                }
12288                let mut len = 0;
12289                for chunk in buffer.text_for_range(selection.start..selection.end) {
12290                    text.push_str(chunk);
12291                    len += chunk.len();
12292                }
12293                clipboard_selections.push(ClipboardSelection {
12294                    len,
12295                    is_entire_line,
12296                    first_line_indent: buffer
12297                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12298                        .len,
12299                });
12300            }
12301        }
12302
12303        self.transact(window, cx, |this, window, cx| {
12304            this.change_selections(Default::default(), window, cx, |s| {
12305                s.select(selections);
12306            });
12307            this.insert("", window, cx);
12308        });
12309        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12310    }
12311
12312    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12314        let item = self.cut_common(true, window, cx);
12315        cx.write_to_clipboard(item);
12316    }
12317
12318    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12320        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12321            s.move_with(|snapshot, sel| {
12322                if sel.is_empty() {
12323                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12324                }
12325                if sel.is_empty() {
12326                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12327                }
12328            });
12329        });
12330        let item = self.cut_common(true, window, cx);
12331        cx.set_global(KillRing(item))
12332    }
12333
12334    pub fn kill_ring_yank(
12335        &mut self,
12336        _: &KillRingYank,
12337        window: &mut Window,
12338        cx: &mut Context<Self>,
12339    ) {
12340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12341        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12342            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12343                (kill_ring.text().to_string(), kill_ring.metadata_json())
12344            } else {
12345                return;
12346            }
12347        } else {
12348            return;
12349        };
12350        self.do_paste(&text, metadata, false, window, cx);
12351    }
12352
12353    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12354        self.do_copy(true, cx);
12355    }
12356
12357    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12358        self.do_copy(false, cx);
12359    }
12360
12361    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12362        let selections = self.selections.all::<Point>(cx);
12363        let buffer = self.buffer.read(cx).read(cx);
12364        let mut text = String::new();
12365
12366        let mut clipboard_selections = Vec::with_capacity(selections.len());
12367        {
12368            let max_point = buffer.max_point();
12369            let mut is_first = true;
12370            for selection in &selections {
12371                let mut start = selection.start;
12372                let mut end = selection.end;
12373                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12374                if is_entire_line {
12375                    start = Point::new(start.row, 0);
12376                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12377                }
12378
12379                let mut trimmed_selections = Vec::new();
12380                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12381                    let row = MultiBufferRow(start.row);
12382                    let first_indent = buffer.indent_size_for_line(row);
12383                    if first_indent.len == 0 || start.column > first_indent.len {
12384                        trimmed_selections.push(start..end);
12385                    } else {
12386                        trimmed_selections.push(
12387                            Point::new(row.0, first_indent.len)
12388                                ..Point::new(row.0, buffer.line_len(row)),
12389                        );
12390                        for row in start.row + 1..=end.row {
12391                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12392                            if row == end.row {
12393                                line_len = end.column;
12394                            }
12395                            if line_len == 0 {
12396                                trimmed_selections
12397                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12398                                continue;
12399                            }
12400                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12401                            if row_indent_size.len >= first_indent.len {
12402                                trimmed_selections.push(
12403                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12404                                );
12405                            } else {
12406                                trimmed_selections.clear();
12407                                trimmed_selections.push(start..end);
12408                                break;
12409                            }
12410                        }
12411                    }
12412                } else {
12413                    trimmed_selections.push(start..end);
12414                }
12415
12416                for trimmed_range in trimmed_selections {
12417                    if is_first {
12418                        is_first = false;
12419                    } else {
12420                        text += "\n";
12421                    }
12422                    let mut len = 0;
12423                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12424                        text.push_str(chunk);
12425                        len += chunk.len();
12426                    }
12427                    clipboard_selections.push(ClipboardSelection {
12428                        len,
12429                        is_entire_line,
12430                        first_line_indent: buffer
12431                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12432                            .len,
12433                    });
12434                }
12435            }
12436        }
12437
12438        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12439            text,
12440            clipboard_selections,
12441        ));
12442    }
12443
12444    pub fn do_paste(
12445        &mut self,
12446        text: &String,
12447        clipboard_selections: Option<Vec<ClipboardSelection>>,
12448        handle_entire_lines: bool,
12449        window: &mut Window,
12450        cx: &mut Context<Self>,
12451    ) {
12452        if self.read_only(cx) {
12453            return;
12454        }
12455
12456        let clipboard_text = Cow::Borrowed(text);
12457
12458        self.transact(window, cx, |this, window, cx| {
12459            let had_active_edit_prediction = this.has_active_edit_prediction();
12460
12461            if let Some(mut clipboard_selections) = clipboard_selections {
12462                let old_selections = this.selections.all::<usize>(cx);
12463                let all_selections_were_entire_line =
12464                    clipboard_selections.iter().all(|s| s.is_entire_line);
12465                let first_selection_indent_column =
12466                    clipboard_selections.first().map(|s| s.first_line_indent);
12467                if clipboard_selections.len() != old_selections.len() {
12468                    clipboard_selections.drain(..);
12469                }
12470                let cursor_offset = this.selections.last::<usize>(cx).head();
12471                let mut auto_indent_on_paste = true;
12472
12473                this.buffer.update(cx, |buffer, cx| {
12474                    let snapshot = buffer.read(cx);
12475                    auto_indent_on_paste = snapshot
12476                        .language_settings_at(cursor_offset, cx)
12477                        .auto_indent_on_paste;
12478
12479                    let mut start_offset = 0;
12480                    let mut edits = Vec::new();
12481                    let mut original_indent_columns = Vec::new();
12482                    for (ix, selection) in old_selections.iter().enumerate() {
12483                        let to_insert;
12484                        let entire_line;
12485                        let original_indent_column;
12486                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12487                            let end_offset = start_offset + clipboard_selection.len;
12488                            to_insert = &clipboard_text[start_offset..end_offset];
12489                            entire_line = clipboard_selection.is_entire_line;
12490                            start_offset = end_offset + 1;
12491                            original_indent_column = Some(clipboard_selection.first_line_indent);
12492                        } else {
12493                            to_insert = clipboard_text.as_str();
12494                            entire_line = all_selections_were_entire_line;
12495                            original_indent_column = first_selection_indent_column
12496                        }
12497
12498                        // If the corresponding selection was empty when this slice of the
12499                        // clipboard text was written, then the entire line containing the
12500                        // selection was copied. If this selection is also currently empty,
12501                        // then paste the line before the current line of the buffer.
12502                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12503                            let column = selection.start.to_point(&snapshot).column as usize;
12504                            let line_start = selection.start - column;
12505                            line_start..line_start
12506                        } else {
12507                            selection.range()
12508                        };
12509
12510                        edits.push((range, to_insert));
12511                        original_indent_columns.push(original_indent_column);
12512                    }
12513                    drop(snapshot);
12514
12515                    buffer.edit(
12516                        edits,
12517                        if auto_indent_on_paste {
12518                            Some(AutoindentMode::Block {
12519                                original_indent_columns,
12520                            })
12521                        } else {
12522                            None
12523                        },
12524                        cx,
12525                    );
12526                });
12527
12528                let selections = this.selections.all::<usize>(cx);
12529                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12530            } else {
12531                this.insert(&clipboard_text, window, cx);
12532            }
12533
12534            let trigger_in_words =
12535                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12536
12537            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12538        });
12539    }
12540
12541    pub fn diff_clipboard_with_selection(
12542        &mut self,
12543        _: &DiffClipboardWithSelection,
12544        window: &mut Window,
12545        cx: &mut Context<Self>,
12546    ) {
12547        let selections = self.selections.all::<usize>(cx);
12548
12549        if selections.is_empty() {
12550            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12551            return;
12552        };
12553
12554        let clipboard_text = match cx.read_from_clipboard() {
12555            Some(item) => match item.entries().first() {
12556                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12557                _ => None,
12558            },
12559            None => None,
12560        };
12561
12562        let Some(clipboard_text) = clipboard_text else {
12563            log::warn!("Clipboard doesn't contain text.");
12564            return;
12565        };
12566
12567        window.dispatch_action(
12568            Box::new(DiffClipboardWithSelectionData {
12569                clipboard_text,
12570                editor: cx.entity(),
12571            }),
12572            cx,
12573        );
12574    }
12575
12576    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12577        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12578        if let Some(item) = cx.read_from_clipboard() {
12579            let entries = item.entries();
12580
12581            match entries.first() {
12582                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12583                // of all the pasted entries.
12584                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12585                    .do_paste(
12586                        clipboard_string.text(),
12587                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12588                        true,
12589                        window,
12590                        cx,
12591                    ),
12592                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12593            }
12594        }
12595    }
12596
12597    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12598        if self.read_only(cx) {
12599            return;
12600        }
12601
12602        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12603
12604        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12605            if let Some((selections, _)) =
12606                self.selection_history.transaction(transaction_id).cloned()
12607            {
12608                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12609                    s.select_anchors(selections.to_vec());
12610                });
12611            } else {
12612                log::error!(
12613                    "No entry in selection_history found for undo. \
12614                     This may correspond to a bug where undo does not update the selection. \
12615                     If this is occurring, please add details to \
12616                     https://github.com/zed-industries/zed/issues/22692"
12617                );
12618            }
12619            self.request_autoscroll(Autoscroll::fit(), cx);
12620            self.unmark_text(window, cx);
12621            self.refresh_edit_prediction(true, false, window, cx);
12622            cx.emit(EditorEvent::Edited { transaction_id });
12623            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12624        }
12625    }
12626
12627    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12628        if self.read_only(cx) {
12629            return;
12630        }
12631
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12633
12634        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12635            if let Some((_, Some(selections))) =
12636                self.selection_history.transaction(transaction_id).cloned()
12637            {
12638                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12639                    s.select_anchors(selections.to_vec());
12640                });
12641            } else {
12642                log::error!(
12643                    "No entry in selection_history found for redo. \
12644                     This may correspond to a bug where undo does not update the selection. \
12645                     If this is occurring, please add details to \
12646                     https://github.com/zed-industries/zed/issues/22692"
12647                );
12648            }
12649            self.request_autoscroll(Autoscroll::fit(), cx);
12650            self.unmark_text(window, cx);
12651            self.refresh_edit_prediction(true, false, window, cx);
12652            cx.emit(EditorEvent::Edited { transaction_id });
12653        }
12654    }
12655
12656    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12657        self.buffer
12658            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12659    }
12660
12661    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12662        self.buffer
12663            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12664    }
12665
12666    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12668        self.change_selections(Default::default(), window, cx, |s| {
12669            s.move_with(|map, selection| {
12670                let cursor = if selection.is_empty() {
12671                    movement::left(map, selection.start)
12672                } else {
12673                    selection.start
12674                };
12675                selection.collapse_to(cursor, SelectionGoal::None);
12676            });
12677        })
12678    }
12679
12680    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12682        self.change_selections(Default::default(), window, cx, |s| {
12683            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12684        })
12685    }
12686
12687    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12689        self.change_selections(Default::default(), window, cx, |s| {
12690            s.move_with(|map, selection| {
12691                let cursor = if selection.is_empty() {
12692                    movement::right(map, selection.end)
12693                } else {
12694                    selection.end
12695                };
12696                selection.collapse_to(cursor, SelectionGoal::None)
12697            });
12698        })
12699    }
12700
12701    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12703        self.change_selections(Default::default(), window, cx, |s| {
12704            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12705        })
12706    }
12707
12708    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12709        if self.take_rename(true, window, cx).is_some() {
12710            return;
12711        }
12712
12713        if self.mode.is_single_line() {
12714            cx.propagate();
12715            return;
12716        }
12717
12718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12719
12720        let text_layout_details = &self.text_layout_details(window);
12721        let selection_count = self.selections.count();
12722        let first_selection = self.selections.first_anchor();
12723
12724        self.change_selections(Default::default(), window, cx, |s| {
12725            s.move_with(|map, selection| {
12726                if !selection.is_empty() {
12727                    selection.goal = SelectionGoal::None;
12728                }
12729                let (cursor, goal) = movement::up(
12730                    map,
12731                    selection.start,
12732                    selection.goal,
12733                    false,
12734                    text_layout_details,
12735                );
12736                selection.collapse_to(cursor, goal);
12737            });
12738        });
12739
12740        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12741        {
12742            cx.propagate();
12743        }
12744    }
12745
12746    pub fn move_up_by_lines(
12747        &mut self,
12748        action: &MoveUpByLines,
12749        window: &mut Window,
12750        cx: &mut Context<Self>,
12751    ) {
12752        if self.take_rename(true, window, cx).is_some() {
12753            return;
12754        }
12755
12756        if self.mode.is_single_line() {
12757            cx.propagate();
12758            return;
12759        }
12760
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12762
12763        let text_layout_details = &self.text_layout_details(window);
12764
12765        self.change_selections(Default::default(), window, cx, |s| {
12766            s.move_with(|map, selection| {
12767                if !selection.is_empty() {
12768                    selection.goal = SelectionGoal::None;
12769                }
12770                let (cursor, goal) = movement::up_by_rows(
12771                    map,
12772                    selection.start,
12773                    action.lines,
12774                    selection.goal,
12775                    false,
12776                    text_layout_details,
12777                );
12778                selection.collapse_to(cursor, goal);
12779            });
12780        })
12781    }
12782
12783    pub fn move_down_by_lines(
12784        &mut self,
12785        action: &MoveDownByLines,
12786        window: &mut Window,
12787        cx: &mut Context<Self>,
12788    ) {
12789        if self.take_rename(true, window, cx).is_some() {
12790            return;
12791        }
12792
12793        if self.mode.is_single_line() {
12794            cx.propagate();
12795            return;
12796        }
12797
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799
12800        let text_layout_details = &self.text_layout_details(window);
12801
12802        self.change_selections(Default::default(), window, cx, |s| {
12803            s.move_with(|map, selection| {
12804                if !selection.is_empty() {
12805                    selection.goal = SelectionGoal::None;
12806                }
12807                let (cursor, goal) = movement::down_by_rows(
12808                    map,
12809                    selection.start,
12810                    action.lines,
12811                    selection.goal,
12812                    false,
12813                    text_layout_details,
12814                );
12815                selection.collapse_to(cursor, goal);
12816            });
12817        })
12818    }
12819
12820    pub fn select_down_by_lines(
12821        &mut self,
12822        action: &SelectDownByLines,
12823        window: &mut Window,
12824        cx: &mut Context<Self>,
12825    ) {
12826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12827        let text_layout_details = &self.text_layout_details(window);
12828        self.change_selections(Default::default(), window, cx, |s| {
12829            s.move_heads_with(|map, head, goal| {
12830                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12831            })
12832        })
12833    }
12834
12835    pub fn select_up_by_lines(
12836        &mut self,
12837        action: &SelectUpByLines,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12842        let text_layout_details = &self.text_layout_details(window);
12843        self.change_selections(Default::default(), window, cx, |s| {
12844            s.move_heads_with(|map, head, goal| {
12845                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12846            })
12847        })
12848    }
12849
12850    pub fn select_page_up(
12851        &mut self,
12852        _: &SelectPageUp,
12853        window: &mut Window,
12854        cx: &mut Context<Self>,
12855    ) {
12856        let Some(row_count) = self.visible_row_count() else {
12857            return;
12858        };
12859
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12861
12862        let text_layout_details = &self.text_layout_details(window);
12863
12864        self.change_selections(Default::default(), window, cx, |s| {
12865            s.move_heads_with(|map, head, goal| {
12866                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12867            })
12868        })
12869    }
12870
12871    pub fn move_page_up(
12872        &mut self,
12873        action: &MovePageUp,
12874        window: &mut Window,
12875        cx: &mut Context<Self>,
12876    ) {
12877        if self.take_rename(true, window, cx).is_some() {
12878            return;
12879        }
12880
12881        if self
12882            .context_menu
12883            .borrow_mut()
12884            .as_mut()
12885            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12886            .unwrap_or(false)
12887        {
12888            return;
12889        }
12890
12891        if matches!(self.mode, EditorMode::SingleLine) {
12892            cx.propagate();
12893            return;
12894        }
12895
12896        let Some(row_count) = self.visible_row_count() else {
12897            return;
12898        };
12899
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12901
12902        let effects = if action.center_cursor {
12903            SelectionEffects::scroll(Autoscroll::center())
12904        } else {
12905            SelectionEffects::default()
12906        };
12907
12908        let text_layout_details = &self.text_layout_details(window);
12909
12910        self.change_selections(effects, window, cx, |s| {
12911            s.move_with(|map, selection| {
12912                if !selection.is_empty() {
12913                    selection.goal = SelectionGoal::None;
12914                }
12915                let (cursor, goal) = movement::up_by_rows(
12916                    map,
12917                    selection.end,
12918                    row_count,
12919                    selection.goal,
12920                    false,
12921                    text_layout_details,
12922                );
12923                selection.collapse_to(cursor, goal);
12924            });
12925        });
12926    }
12927
12928    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12930        let text_layout_details = &self.text_layout_details(window);
12931        self.change_selections(Default::default(), window, cx, |s| {
12932            s.move_heads_with(|map, head, goal| {
12933                movement::up(map, head, goal, false, text_layout_details)
12934            })
12935        })
12936    }
12937
12938    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12939        self.take_rename(true, window, cx);
12940
12941        if self.mode.is_single_line() {
12942            cx.propagate();
12943            return;
12944        }
12945
12946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12947
12948        let text_layout_details = &self.text_layout_details(window);
12949        let selection_count = self.selections.count();
12950        let first_selection = self.selections.first_anchor();
12951
12952        self.change_selections(Default::default(), window, cx, |s| {
12953            s.move_with(|map, selection| {
12954                if !selection.is_empty() {
12955                    selection.goal = SelectionGoal::None;
12956                }
12957                let (cursor, goal) = movement::down(
12958                    map,
12959                    selection.end,
12960                    selection.goal,
12961                    false,
12962                    text_layout_details,
12963                );
12964                selection.collapse_to(cursor, goal);
12965            });
12966        });
12967
12968        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12969        {
12970            cx.propagate();
12971        }
12972    }
12973
12974    pub fn select_page_down(
12975        &mut self,
12976        _: &SelectPageDown,
12977        window: &mut Window,
12978        cx: &mut Context<Self>,
12979    ) {
12980        let Some(row_count) = self.visible_row_count() else {
12981            return;
12982        };
12983
12984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12985
12986        let text_layout_details = &self.text_layout_details(window);
12987
12988        self.change_selections(Default::default(), window, cx, |s| {
12989            s.move_heads_with(|map, head, goal| {
12990                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12991            })
12992        })
12993    }
12994
12995    pub fn move_page_down(
12996        &mut self,
12997        action: &MovePageDown,
12998        window: &mut Window,
12999        cx: &mut Context<Self>,
13000    ) {
13001        if self.take_rename(true, window, cx).is_some() {
13002            return;
13003        }
13004
13005        if self
13006            .context_menu
13007            .borrow_mut()
13008            .as_mut()
13009            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13010            .unwrap_or(false)
13011        {
13012            return;
13013        }
13014
13015        if matches!(self.mode, EditorMode::SingleLine) {
13016            cx.propagate();
13017            return;
13018        }
13019
13020        let Some(row_count) = self.visible_row_count() else {
13021            return;
13022        };
13023
13024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13025
13026        let effects = if action.center_cursor {
13027            SelectionEffects::scroll(Autoscroll::center())
13028        } else {
13029            SelectionEffects::default()
13030        };
13031
13032        let text_layout_details = &self.text_layout_details(window);
13033        self.change_selections(effects, window, cx, |s| {
13034            s.move_with(|map, selection| {
13035                if !selection.is_empty() {
13036                    selection.goal = SelectionGoal::None;
13037                }
13038                let (cursor, goal) = movement::down_by_rows(
13039                    map,
13040                    selection.end,
13041                    row_count,
13042                    selection.goal,
13043                    false,
13044                    text_layout_details,
13045                );
13046                selection.collapse_to(cursor, goal);
13047            });
13048        });
13049    }
13050
13051    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13053        let text_layout_details = &self.text_layout_details(window);
13054        self.change_selections(Default::default(), window, cx, |s| {
13055            s.move_heads_with(|map, head, goal| {
13056                movement::down(map, head, goal, false, text_layout_details)
13057            })
13058        });
13059    }
13060
13061    pub fn context_menu_first(
13062        &mut self,
13063        _: &ContextMenuFirst,
13064        window: &mut Window,
13065        cx: &mut Context<Self>,
13066    ) {
13067        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13068            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13069        }
13070    }
13071
13072    pub fn context_menu_prev(
13073        &mut self,
13074        _: &ContextMenuPrevious,
13075        window: &mut Window,
13076        cx: &mut Context<Self>,
13077    ) {
13078        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13079            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13080        }
13081    }
13082
13083    pub fn context_menu_next(
13084        &mut self,
13085        _: &ContextMenuNext,
13086        window: &mut Window,
13087        cx: &mut Context<Self>,
13088    ) {
13089        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13090            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13091        }
13092    }
13093
13094    pub fn context_menu_last(
13095        &mut self,
13096        _: &ContextMenuLast,
13097        window: &mut Window,
13098        cx: &mut Context<Self>,
13099    ) {
13100        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13101            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13102        }
13103    }
13104
13105    pub fn signature_help_prev(
13106        &mut self,
13107        _: &SignatureHelpPrevious,
13108        _: &mut Window,
13109        cx: &mut Context<Self>,
13110    ) {
13111        if let Some(popover) = self.signature_help_state.popover_mut() {
13112            if popover.current_signature == 0 {
13113                popover.current_signature = popover.signatures.len() - 1;
13114            } else {
13115                popover.current_signature -= 1;
13116            }
13117            cx.notify();
13118        }
13119    }
13120
13121    pub fn signature_help_next(
13122        &mut self,
13123        _: &SignatureHelpNext,
13124        _: &mut Window,
13125        cx: &mut Context<Self>,
13126    ) {
13127        if let Some(popover) = self.signature_help_state.popover_mut() {
13128            if popover.current_signature + 1 == popover.signatures.len() {
13129                popover.current_signature = 0;
13130            } else {
13131                popover.current_signature += 1;
13132            }
13133            cx.notify();
13134        }
13135    }
13136
13137    pub fn move_to_previous_word_start(
13138        &mut self,
13139        _: &MoveToPreviousWordStart,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13144        self.change_selections(Default::default(), window, cx, |s| {
13145            s.move_cursors_with(|map, head, _| {
13146                (
13147                    movement::previous_word_start(map, head),
13148                    SelectionGoal::None,
13149                )
13150            });
13151        })
13152    }
13153
13154    pub fn move_to_previous_subword_start(
13155        &mut self,
13156        _: &MoveToPreviousSubwordStart,
13157        window: &mut Window,
13158        cx: &mut Context<Self>,
13159    ) {
13160        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13161        self.change_selections(Default::default(), window, cx, |s| {
13162            s.move_cursors_with(|map, head, _| {
13163                (
13164                    movement::previous_subword_start(map, head),
13165                    SelectionGoal::None,
13166                )
13167            });
13168        })
13169    }
13170
13171    pub fn select_to_previous_word_start(
13172        &mut self,
13173        _: &SelectToPreviousWordStart,
13174        window: &mut Window,
13175        cx: &mut Context<Self>,
13176    ) {
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178        self.change_selections(Default::default(), window, cx, |s| {
13179            s.move_heads_with(|map, head, _| {
13180                (
13181                    movement::previous_word_start(map, head),
13182                    SelectionGoal::None,
13183                )
13184            });
13185        })
13186    }
13187
13188    pub fn select_to_previous_subword_start(
13189        &mut self,
13190        _: &SelectToPreviousSubwordStart,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13195        self.change_selections(Default::default(), window, cx, |s| {
13196            s.move_heads_with(|map, head, _| {
13197                (
13198                    movement::previous_subword_start(map, head),
13199                    SelectionGoal::None,
13200                )
13201            });
13202        })
13203    }
13204
13205    pub fn delete_to_previous_word_start(
13206        &mut self,
13207        action: &DeleteToPreviousWordStart,
13208        window: &mut Window,
13209        cx: &mut Context<Self>,
13210    ) {
13211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13212        self.transact(window, cx, |this, window, cx| {
13213            this.select_autoclose_pair(window, cx);
13214            this.change_selections(Default::default(), window, cx, |s| {
13215                s.move_with(|map, selection| {
13216                    if selection.is_empty() {
13217                        let mut cursor = if action.ignore_newlines {
13218                            movement::previous_word_start(map, selection.head())
13219                        } else {
13220                            movement::previous_word_start_or_newline(map, selection.head())
13221                        };
13222                        cursor = movement::adjust_greedy_deletion(
13223                            map,
13224                            selection.head(),
13225                            cursor,
13226                            action.ignore_brackets,
13227                        );
13228                        selection.set_head(cursor, SelectionGoal::None);
13229                    }
13230                });
13231            });
13232            this.insert("", window, cx);
13233        });
13234    }
13235
13236    pub fn delete_to_previous_subword_start(
13237        &mut self,
13238        _: &DeleteToPreviousSubwordStart,
13239        window: &mut Window,
13240        cx: &mut Context<Self>,
13241    ) {
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13243        self.transact(window, cx, |this, window, cx| {
13244            this.select_autoclose_pair(window, cx);
13245            this.change_selections(Default::default(), window, cx, |s| {
13246                s.move_with(|map, selection| {
13247                    if selection.is_empty() {
13248                        let mut cursor = movement::previous_subword_start(map, selection.head());
13249                        cursor =
13250                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13251                        selection.set_head(cursor, SelectionGoal::None);
13252                    }
13253                });
13254            });
13255            this.insert("", window, cx);
13256        });
13257    }
13258
13259    pub fn move_to_next_word_end(
13260        &mut self,
13261        _: &MoveToNextWordEnd,
13262        window: &mut Window,
13263        cx: &mut Context<Self>,
13264    ) {
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266        self.change_selections(Default::default(), window, cx, |s| {
13267            s.move_cursors_with(|map, head, _| {
13268                (movement::next_word_end(map, head), SelectionGoal::None)
13269            });
13270        })
13271    }
13272
13273    pub fn move_to_next_subword_end(
13274        &mut self,
13275        _: &MoveToNextSubwordEnd,
13276        window: &mut Window,
13277        cx: &mut Context<Self>,
13278    ) {
13279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13280        self.change_selections(Default::default(), window, cx, |s| {
13281            s.move_cursors_with(|map, head, _| {
13282                (movement::next_subword_end(map, head), SelectionGoal::None)
13283            });
13284        })
13285    }
13286
13287    pub fn select_to_next_word_end(
13288        &mut self,
13289        _: &SelectToNextWordEnd,
13290        window: &mut Window,
13291        cx: &mut Context<Self>,
13292    ) {
13293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13294        self.change_selections(Default::default(), window, cx, |s| {
13295            s.move_heads_with(|map, head, _| {
13296                (movement::next_word_end(map, head), SelectionGoal::None)
13297            });
13298        })
13299    }
13300
13301    pub fn select_to_next_subword_end(
13302        &mut self,
13303        _: &SelectToNextSubwordEnd,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308        self.change_selections(Default::default(), window, cx, |s| {
13309            s.move_heads_with(|map, head, _| {
13310                (movement::next_subword_end(map, head), SelectionGoal::None)
13311            });
13312        })
13313    }
13314
13315    pub fn delete_to_next_word_end(
13316        &mut self,
13317        action: &DeleteToNextWordEnd,
13318        window: &mut Window,
13319        cx: &mut Context<Self>,
13320    ) {
13321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13322        self.transact(window, cx, |this, window, cx| {
13323            this.change_selections(Default::default(), window, cx, |s| {
13324                s.move_with(|map, selection| {
13325                    if selection.is_empty() {
13326                        let mut cursor = if action.ignore_newlines {
13327                            movement::next_word_end(map, selection.head())
13328                        } else {
13329                            movement::next_word_end_or_newline(map, selection.head())
13330                        };
13331                        cursor = movement::adjust_greedy_deletion(
13332                            map,
13333                            selection.head(),
13334                            cursor,
13335                            action.ignore_brackets,
13336                        );
13337                        selection.set_head(cursor, SelectionGoal::None);
13338                    }
13339                });
13340            });
13341            this.insert("", window, cx);
13342        });
13343    }
13344
13345    pub fn delete_to_next_subword_end(
13346        &mut self,
13347        _: &DeleteToNextSubwordEnd,
13348        window: &mut Window,
13349        cx: &mut Context<Self>,
13350    ) {
13351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13352        self.transact(window, cx, |this, window, cx| {
13353            this.change_selections(Default::default(), window, cx, |s| {
13354                s.move_with(|map, selection| {
13355                    if selection.is_empty() {
13356                        let mut cursor = movement::next_subword_end(map, selection.head());
13357                        cursor =
13358                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13359                        selection.set_head(cursor, SelectionGoal::None);
13360                    }
13361                });
13362            });
13363            this.insert("", window, cx);
13364        });
13365    }
13366
13367    pub fn move_to_beginning_of_line(
13368        &mut self,
13369        action: &MoveToBeginningOfLine,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) {
13373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13374        self.change_selections(Default::default(), window, cx, |s| {
13375            s.move_cursors_with(|map, head, _| {
13376                (
13377                    movement::indented_line_beginning(
13378                        map,
13379                        head,
13380                        action.stop_at_soft_wraps,
13381                        action.stop_at_indent,
13382                    ),
13383                    SelectionGoal::None,
13384                )
13385            });
13386        })
13387    }
13388
13389    pub fn select_to_beginning_of_line(
13390        &mut self,
13391        action: &SelectToBeginningOfLine,
13392        window: &mut Window,
13393        cx: &mut Context<Self>,
13394    ) {
13395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13396        self.change_selections(Default::default(), window, cx, |s| {
13397            s.move_heads_with(|map, head, _| {
13398                (
13399                    movement::indented_line_beginning(
13400                        map,
13401                        head,
13402                        action.stop_at_soft_wraps,
13403                        action.stop_at_indent,
13404                    ),
13405                    SelectionGoal::None,
13406                )
13407            });
13408        });
13409    }
13410
13411    pub fn delete_to_beginning_of_line(
13412        &mut self,
13413        action: &DeleteToBeginningOfLine,
13414        window: &mut Window,
13415        cx: &mut Context<Self>,
13416    ) {
13417        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13418        self.transact(window, cx, |this, window, cx| {
13419            this.change_selections(Default::default(), window, cx, |s| {
13420                s.move_with(|_, selection| {
13421                    selection.reversed = true;
13422                });
13423            });
13424
13425            this.select_to_beginning_of_line(
13426                &SelectToBeginningOfLine {
13427                    stop_at_soft_wraps: false,
13428                    stop_at_indent: action.stop_at_indent,
13429                },
13430                window,
13431                cx,
13432            );
13433            this.backspace(&Backspace, window, cx);
13434        });
13435    }
13436
13437    pub fn move_to_end_of_line(
13438        &mut self,
13439        action: &MoveToEndOfLine,
13440        window: &mut Window,
13441        cx: &mut Context<Self>,
13442    ) {
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.move_cursors_with(|map, head, _| {
13446                (
13447                    movement::line_end(map, head, action.stop_at_soft_wraps),
13448                    SelectionGoal::None,
13449                )
13450            });
13451        })
13452    }
13453
13454    pub fn select_to_end_of_line(
13455        &mut self,
13456        action: &SelectToEndOfLine,
13457        window: &mut Window,
13458        cx: &mut Context<Self>,
13459    ) {
13460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13461        self.change_selections(Default::default(), window, cx, |s| {
13462            s.move_heads_with(|map, head, _| {
13463                (
13464                    movement::line_end(map, head, action.stop_at_soft_wraps),
13465                    SelectionGoal::None,
13466                )
13467            });
13468        })
13469    }
13470
13471    pub fn delete_to_end_of_line(
13472        &mut self,
13473        _: &DeleteToEndOfLine,
13474        window: &mut Window,
13475        cx: &mut Context<Self>,
13476    ) {
13477        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13478        self.transact(window, cx, |this, window, cx| {
13479            this.select_to_end_of_line(
13480                &SelectToEndOfLine {
13481                    stop_at_soft_wraps: false,
13482                },
13483                window,
13484                cx,
13485            );
13486            this.delete(&Delete, window, cx);
13487        });
13488    }
13489
13490    pub fn cut_to_end_of_line(
13491        &mut self,
13492        action: &CutToEndOfLine,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13497        self.transact(window, cx, |this, window, cx| {
13498            this.select_to_end_of_line(
13499                &SelectToEndOfLine {
13500                    stop_at_soft_wraps: false,
13501                },
13502                window,
13503                cx,
13504            );
13505            if !action.stop_at_newlines {
13506                this.change_selections(Default::default(), window, cx, |s| {
13507                    s.move_with(|_, sel| {
13508                        if sel.is_empty() {
13509                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13510                        }
13511                    });
13512                });
13513            }
13514            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13515            let item = this.cut_common(false, window, cx);
13516            cx.write_to_clipboard(item);
13517        });
13518    }
13519
13520    pub fn move_to_start_of_paragraph(
13521        &mut self,
13522        _: &MoveToStartOfParagraph,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        if matches!(self.mode, EditorMode::SingleLine) {
13527            cx.propagate();
13528            return;
13529        }
13530        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13531        self.change_selections(Default::default(), window, cx, |s| {
13532            s.move_with(|map, selection| {
13533                selection.collapse_to(
13534                    movement::start_of_paragraph(map, selection.head(), 1),
13535                    SelectionGoal::None,
13536                )
13537            });
13538        })
13539    }
13540
13541    pub fn move_to_end_of_paragraph(
13542        &mut self,
13543        _: &MoveToEndOfParagraph,
13544        window: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        if matches!(self.mode, EditorMode::SingleLine) {
13548            cx.propagate();
13549            return;
13550        }
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_with(|map, selection| {
13554                selection.collapse_to(
13555                    movement::end_of_paragraph(map, selection.head(), 1),
13556                    SelectionGoal::None,
13557                )
13558            });
13559        })
13560    }
13561
13562    pub fn select_to_start_of_paragraph(
13563        &mut self,
13564        _: &SelectToStartOfParagraph,
13565        window: &mut Window,
13566        cx: &mut Context<Self>,
13567    ) {
13568        if matches!(self.mode, EditorMode::SingleLine) {
13569            cx.propagate();
13570            return;
13571        }
13572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13573        self.change_selections(Default::default(), window, cx, |s| {
13574            s.move_heads_with(|map, head, _| {
13575                (
13576                    movement::start_of_paragraph(map, head, 1),
13577                    SelectionGoal::None,
13578                )
13579            });
13580        })
13581    }
13582
13583    pub fn select_to_end_of_paragraph(
13584        &mut self,
13585        _: &SelectToEndOfParagraph,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        if matches!(self.mode, EditorMode::SingleLine) {
13590            cx.propagate();
13591            return;
13592        }
13593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.move_heads_with(|map, head, _| {
13596                (
13597                    movement::end_of_paragraph(map, head, 1),
13598                    SelectionGoal::None,
13599                )
13600            });
13601        })
13602    }
13603
13604    pub fn move_to_start_of_excerpt(
13605        &mut self,
13606        _: &MoveToStartOfExcerpt,
13607        window: &mut Window,
13608        cx: &mut Context<Self>,
13609    ) {
13610        if matches!(self.mode, EditorMode::SingleLine) {
13611            cx.propagate();
13612            return;
13613        }
13614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13615        self.change_selections(Default::default(), window, cx, |s| {
13616            s.move_with(|map, selection| {
13617                selection.collapse_to(
13618                    movement::start_of_excerpt(
13619                        map,
13620                        selection.head(),
13621                        workspace::searchable::Direction::Prev,
13622                    ),
13623                    SelectionGoal::None,
13624                )
13625            });
13626        })
13627    }
13628
13629    pub fn move_to_start_of_next_excerpt(
13630        &mut self,
13631        _: &MoveToStartOfNextExcerpt,
13632        window: &mut Window,
13633        cx: &mut Context<Self>,
13634    ) {
13635        if matches!(self.mode, EditorMode::SingleLine) {
13636            cx.propagate();
13637            return;
13638        }
13639
13640        self.change_selections(Default::default(), window, cx, |s| {
13641            s.move_with(|map, selection| {
13642                selection.collapse_to(
13643                    movement::start_of_excerpt(
13644                        map,
13645                        selection.head(),
13646                        workspace::searchable::Direction::Next,
13647                    ),
13648                    SelectionGoal::None,
13649                )
13650            });
13651        })
13652    }
13653
13654    pub fn move_to_end_of_excerpt(
13655        &mut self,
13656        _: &MoveToEndOfExcerpt,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        if matches!(self.mode, EditorMode::SingleLine) {
13661            cx.propagate();
13662            return;
13663        }
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13665        self.change_selections(Default::default(), window, cx, |s| {
13666            s.move_with(|map, selection| {
13667                selection.collapse_to(
13668                    movement::end_of_excerpt(
13669                        map,
13670                        selection.head(),
13671                        workspace::searchable::Direction::Next,
13672                    ),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn move_to_end_of_previous_excerpt(
13680        &mut self,
13681        _: &MoveToEndOfPreviousExcerpt,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        if matches!(self.mode, EditorMode::SingleLine) {
13686            cx.propagate();
13687            return;
13688        }
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690        self.change_selections(Default::default(), window, cx, |s| {
13691            s.move_with(|map, selection| {
13692                selection.collapse_to(
13693                    movement::end_of_excerpt(
13694                        map,
13695                        selection.head(),
13696                        workspace::searchable::Direction::Prev,
13697                    ),
13698                    SelectionGoal::None,
13699                )
13700            });
13701        })
13702    }
13703
13704    pub fn select_to_start_of_excerpt(
13705        &mut self,
13706        _: &SelectToStartOfExcerpt,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        if matches!(self.mode, EditorMode::SingleLine) {
13711            cx.propagate();
13712            return;
13713        }
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13715        self.change_selections(Default::default(), window, cx, |s| {
13716            s.move_heads_with(|map, head, _| {
13717                (
13718                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13719                    SelectionGoal::None,
13720                )
13721            });
13722        })
13723    }
13724
13725    pub fn select_to_start_of_next_excerpt(
13726        &mut self,
13727        _: &SelectToStartOfNextExcerpt,
13728        window: &mut Window,
13729        cx: &mut Context<Self>,
13730    ) {
13731        if matches!(self.mode, EditorMode::SingleLine) {
13732            cx.propagate();
13733            return;
13734        }
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_heads_with(|map, head, _| {
13738                (
13739                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13740                    SelectionGoal::None,
13741                )
13742            });
13743        })
13744    }
13745
13746    pub fn select_to_end_of_excerpt(
13747        &mut self,
13748        _: &SelectToEndOfExcerpt,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        if matches!(self.mode, EditorMode::SingleLine) {
13753            cx.propagate();
13754            return;
13755        }
13756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13757        self.change_selections(Default::default(), window, cx, |s| {
13758            s.move_heads_with(|map, head, _| {
13759                (
13760                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn select_to_end_of_previous_excerpt(
13768        &mut self,
13769        _: &SelectToEndOfPreviousExcerpt,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_heads_with(|map, head, _| {
13780                (
13781                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13782                    SelectionGoal::None,
13783                )
13784            });
13785        })
13786    }
13787
13788    pub fn move_to_beginning(
13789        &mut self,
13790        _: &MoveToBeginning,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) {
13794        if matches!(self.mode, EditorMode::SingleLine) {
13795            cx.propagate();
13796            return;
13797        }
13798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13799        self.change_selections(Default::default(), window, cx, |s| {
13800            s.select_ranges(vec![0..0]);
13801        });
13802    }
13803
13804    pub fn select_to_beginning(
13805        &mut self,
13806        _: &SelectToBeginning,
13807        window: &mut Window,
13808        cx: &mut Context<Self>,
13809    ) {
13810        let mut selection = self.selections.last::<Point>(cx);
13811        selection.set_head(Point::zero(), SelectionGoal::None);
13812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13813        self.change_selections(Default::default(), window, cx, |s| {
13814            s.select(vec![selection]);
13815        });
13816    }
13817
13818    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13819        if matches!(self.mode, EditorMode::SingleLine) {
13820            cx.propagate();
13821            return;
13822        }
13823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13824        let cursor = self.buffer.read(cx).read(cx).len();
13825        self.change_selections(Default::default(), window, cx, |s| {
13826            s.select_ranges(vec![cursor..cursor])
13827        });
13828    }
13829
13830    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13831        self.nav_history = nav_history;
13832    }
13833
13834    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13835        self.nav_history.as_ref()
13836    }
13837
13838    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13839        self.push_to_nav_history(
13840            self.selections.newest_anchor().head(),
13841            None,
13842            false,
13843            true,
13844            cx,
13845        );
13846    }
13847
13848    fn push_to_nav_history(
13849        &mut self,
13850        cursor_anchor: Anchor,
13851        new_position: Option<Point>,
13852        is_deactivate: bool,
13853        always: bool,
13854        cx: &mut Context<Self>,
13855    ) {
13856        if let Some(nav_history) = self.nav_history.as_mut() {
13857            let buffer = self.buffer.read(cx).read(cx);
13858            let cursor_position = cursor_anchor.to_point(&buffer);
13859            let scroll_state = self.scroll_manager.anchor();
13860            let scroll_top_row = scroll_state.top_row(&buffer);
13861            drop(buffer);
13862
13863            if let Some(new_position) = new_position {
13864                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13865                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13866                    return;
13867                }
13868            }
13869
13870            nav_history.push(
13871                Some(NavigationData {
13872                    cursor_anchor,
13873                    cursor_position,
13874                    scroll_anchor: scroll_state,
13875                    scroll_top_row,
13876                }),
13877                cx,
13878            );
13879            cx.emit(EditorEvent::PushedToNavHistory {
13880                anchor: cursor_anchor,
13881                is_deactivate,
13882            })
13883        }
13884    }
13885
13886    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13887        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13888        let buffer = self.buffer.read(cx).snapshot(cx);
13889        let mut selection = self.selections.first::<usize>(cx);
13890        selection.set_head(buffer.len(), SelectionGoal::None);
13891        self.change_selections(Default::default(), window, cx, |s| {
13892            s.select(vec![selection]);
13893        });
13894    }
13895
13896    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13898        let end = self.buffer.read(cx).read(cx).len();
13899        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13900            s.select_ranges(vec![0..end]);
13901        });
13902    }
13903
13904    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13906        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13907        let mut selections = self.selections.all::<Point>(cx);
13908        let max_point = display_map.buffer_snapshot.max_point();
13909        for selection in &mut selections {
13910            let rows = selection.spanned_rows(true, &display_map);
13911            selection.start = Point::new(rows.start.0, 0);
13912            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13913            selection.reversed = false;
13914        }
13915        self.change_selections(Default::default(), window, cx, |s| {
13916            s.select(selections);
13917        });
13918    }
13919
13920    pub fn split_selection_into_lines(
13921        &mut self,
13922        action: &SplitSelectionIntoLines,
13923        window: &mut Window,
13924        cx: &mut Context<Self>,
13925    ) {
13926        let selections = self
13927            .selections
13928            .all::<Point>(cx)
13929            .into_iter()
13930            .map(|selection| selection.start..selection.end)
13931            .collect::<Vec<_>>();
13932        self.unfold_ranges(&selections, true, true, cx);
13933
13934        let mut new_selection_ranges = Vec::new();
13935        {
13936            let buffer = self.buffer.read(cx).read(cx);
13937            for selection in selections {
13938                for row in selection.start.row..selection.end.row {
13939                    let line_start = Point::new(row, 0);
13940                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13941
13942                    if action.keep_selections {
13943                        // Keep the selection range for each line
13944                        let selection_start = if row == selection.start.row {
13945                            selection.start
13946                        } else {
13947                            line_start
13948                        };
13949                        new_selection_ranges.push(selection_start..line_end);
13950                    } else {
13951                        // Collapse to cursor at end of line
13952                        new_selection_ranges.push(line_end..line_end);
13953                    }
13954                }
13955
13956                let is_multiline_selection = selection.start.row != selection.end.row;
13957                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13958                // so this action feels more ergonomic when paired with other selection operations
13959                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13960                if !should_skip_last {
13961                    if action.keep_selections {
13962                        if is_multiline_selection {
13963                            let line_start = Point::new(selection.end.row, 0);
13964                            new_selection_ranges.push(line_start..selection.end);
13965                        } else {
13966                            new_selection_ranges.push(selection.start..selection.end);
13967                        }
13968                    } else {
13969                        new_selection_ranges.push(selection.end..selection.end);
13970                    }
13971                }
13972            }
13973        }
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.select_ranges(new_selection_ranges);
13976        });
13977    }
13978
13979    pub fn add_selection_above(
13980        &mut self,
13981        _: &AddSelectionAbove,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        self.add_selection(true, window, cx);
13986    }
13987
13988    pub fn add_selection_below(
13989        &mut self,
13990        _: &AddSelectionBelow,
13991        window: &mut Window,
13992        cx: &mut Context<Self>,
13993    ) {
13994        self.add_selection(false, window, cx);
13995    }
13996
13997    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13999
14000        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14001        let all_selections = self.selections.all::<Point>(cx);
14002        let text_layout_details = self.text_layout_details(window);
14003
14004        let (mut columnar_selections, new_selections_to_columnarize) = {
14005            if let Some(state) = self.add_selections_state.as_ref() {
14006                let columnar_selection_ids: HashSet<_> = state
14007                    .groups
14008                    .iter()
14009                    .flat_map(|group| group.stack.iter())
14010                    .copied()
14011                    .collect();
14012
14013                all_selections
14014                    .into_iter()
14015                    .partition(|s| columnar_selection_ids.contains(&s.id))
14016            } else {
14017                (Vec::new(), all_selections)
14018            }
14019        };
14020
14021        let mut state = self
14022            .add_selections_state
14023            .take()
14024            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14025
14026        for selection in new_selections_to_columnarize {
14027            let range = selection.display_range(&display_map).sorted();
14028            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14029            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14030            let positions = start_x.min(end_x)..start_x.max(end_x);
14031            let mut stack = Vec::new();
14032            for row in range.start.row().0..=range.end.row().0 {
14033                if let Some(selection) = self.selections.build_columnar_selection(
14034                    &display_map,
14035                    DisplayRow(row),
14036                    &positions,
14037                    selection.reversed,
14038                    &text_layout_details,
14039                ) {
14040                    stack.push(selection.id);
14041                    columnar_selections.push(selection);
14042                }
14043            }
14044            if !stack.is_empty() {
14045                if above {
14046                    stack.reverse();
14047                }
14048                state.groups.push(AddSelectionsGroup { above, stack });
14049            }
14050        }
14051
14052        let mut final_selections = Vec::new();
14053        let end_row = if above {
14054            DisplayRow(0)
14055        } else {
14056            display_map.max_point().row()
14057        };
14058
14059        let mut last_added_item_per_group = HashMap::default();
14060        for group in state.groups.iter_mut() {
14061            if let Some(last_id) = group.stack.last() {
14062                last_added_item_per_group.insert(*last_id, group);
14063            }
14064        }
14065
14066        for selection in columnar_selections {
14067            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14068                if above == group.above {
14069                    let range = selection.display_range(&display_map).sorted();
14070                    debug_assert_eq!(range.start.row(), range.end.row());
14071                    let mut row = range.start.row();
14072                    let positions =
14073                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14074                            px(start)..px(end)
14075                        } else {
14076                            let start_x =
14077                                display_map.x_for_display_point(range.start, &text_layout_details);
14078                            let end_x =
14079                                display_map.x_for_display_point(range.end, &text_layout_details);
14080                            start_x.min(end_x)..start_x.max(end_x)
14081                        };
14082
14083                    let mut maybe_new_selection = None;
14084                    while row != end_row {
14085                        if above {
14086                            row.0 -= 1;
14087                        } else {
14088                            row.0 += 1;
14089                        }
14090                        if let Some(new_selection) = self.selections.build_columnar_selection(
14091                            &display_map,
14092                            row,
14093                            &positions,
14094                            selection.reversed,
14095                            &text_layout_details,
14096                        ) {
14097                            maybe_new_selection = Some(new_selection);
14098                            break;
14099                        }
14100                    }
14101
14102                    if let Some(new_selection) = maybe_new_selection {
14103                        group.stack.push(new_selection.id);
14104                        if above {
14105                            final_selections.push(new_selection);
14106                            final_selections.push(selection);
14107                        } else {
14108                            final_selections.push(selection);
14109                            final_selections.push(new_selection);
14110                        }
14111                    } else {
14112                        final_selections.push(selection);
14113                    }
14114                } else {
14115                    group.stack.pop();
14116                }
14117            } else {
14118                final_selections.push(selection);
14119            }
14120        }
14121
14122        self.change_selections(Default::default(), window, cx, |s| {
14123            s.select(final_selections);
14124        });
14125
14126        let final_selection_ids: HashSet<_> = self
14127            .selections
14128            .all::<Point>(cx)
14129            .iter()
14130            .map(|s| s.id)
14131            .collect();
14132        state.groups.retain_mut(|group| {
14133            // selections might get merged above so we remove invalid items from stacks
14134            group.stack.retain(|id| final_selection_ids.contains(id));
14135
14136            // single selection in stack can be treated as initial state
14137            group.stack.len() > 1
14138        });
14139
14140        if !state.groups.is_empty() {
14141            self.add_selections_state = Some(state);
14142        }
14143    }
14144
14145    fn select_match_ranges(
14146        &mut self,
14147        range: Range<usize>,
14148        reversed: bool,
14149        replace_newest: bool,
14150        auto_scroll: Option<Autoscroll>,
14151        window: &mut Window,
14152        cx: &mut Context<Editor>,
14153    ) {
14154        self.unfold_ranges(
14155            std::slice::from_ref(&range),
14156            false,
14157            auto_scroll.is_some(),
14158            cx,
14159        );
14160        let effects = if let Some(scroll) = auto_scroll {
14161            SelectionEffects::scroll(scroll)
14162        } else {
14163            SelectionEffects::no_scroll()
14164        };
14165        self.change_selections(effects, window, cx, |s| {
14166            if replace_newest {
14167                s.delete(s.newest_anchor().id);
14168            }
14169            if reversed {
14170                s.insert_range(range.end..range.start);
14171            } else {
14172                s.insert_range(range);
14173            }
14174        });
14175    }
14176
14177    pub fn select_next_match_internal(
14178        &mut self,
14179        display_map: &DisplaySnapshot,
14180        replace_newest: bool,
14181        autoscroll: Option<Autoscroll>,
14182        window: &mut Window,
14183        cx: &mut Context<Self>,
14184    ) -> Result<()> {
14185        let buffer = &display_map.buffer_snapshot;
14186        let mut selections = self.selections.all::<usize>(cx);
14187        if let Some(mut select_next_state) = self.select_next_state.take() {
14188            let query = &select_next_state.query;
14189            if !select_next_state.done {
14190                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14191                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14192                let mut next_selected_range = None;
14193
14194                let bytes_after_last_selection =
14195                    buffer.bytes_in_range(last_selection.end..buffer.len());
14196                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14197                let query_matches = query
14198                    .stream_find_iter(bytes_after_last_selection)
14199                    .map(|result| (last_selection.end, result))
14200                    .chain(
14201                        query
14202                            .stream_find_iter(bytes_before_first_selection)
14203                            .map(|result| (0, result)),
14204                    );
14205
14206                for (start_offset, query_match) in query_matches {
14207                    let query_match = query_match.unwrap(); // can only fail due to I/O
14208                    let offset_range =
14209                        start_offset + query_match.start()..start_offset + query_match.end();
14210
14211                    if !select_next_state.wordwise
14212                        || (!buffer.is_inside_word(offset_range.start, false)
14213                            && !buffer.is_inside_word(offset_range.end, false))
14214                    {
14215                        // TODO: This is n^2, because we might check all the selections
14216                        if !selections
14217                            .iter()
14218                            .any(|selection| selection.range().overlaps(&offset_range))
14219                        {
14220                            next_selected_range = Some(offset_range);
14221                            break;
14222                        }
14223                    }
14224                }
14225
14226                if let Some(next_selected_range) = next_selected_range {
14227                    self.select_match_ranges(
14228                        next_selected_range,
14229                        last_selection.reversed,
14230                        replace_newest,
14231                        autoscroll,
14232                        window,
14233                        cx,
14234                    );
14235                } else {
14236                    select_next_state.done = true;
14237                }
14238            }
14239
14240            self.select_next_state = Some(select_next_state);
14241        } else {
14242            let mut only_carets = true;
14243            let mut same_text_selected = true;
14244            let mut selected_text = None;
14245
14246            let mut selections_iter = selections.iter().peekable();
14247            while let Some(selection) = selections_iter.next() {
14248                if selection.start != selection.end {
14249                    only_carets = false;
14250                }
14251
14252                if same_text_selected {
14253                    if selected_text.is_none() {
14254                        selected_text =
14255                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14256                    }
14257
14258                    if let Some(next_selection) = selections_iter.peek() {
14259                        if next_selection.range().len() == selection.range().len() {
14260                            let next_selected_text = buffer
14261                                .text_for_range(next_selection.range())
14262                                .collect::<String>();
14263                            if Some(next_selected_text) != selected_text {
14264                                same_text_selected = false;
14265                                selected_text = None;
14266                            }
14267                        } else {
14268                            same_text_selected = false;
14269                            selected_text = None;
14270                        }
14271                    }
14272                }
14273            }
14274
14275            if only_carets {
14276                for selection in &mut selections {
14277                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14278                    selection.start = word_range.start;
14279                    selection.end = word_range.end;
14280                    selection.goal = SelectionGoal::None;
14281                    selection.reversed = false;
14282                    self.select_match_ranges(
14283                        selection.start..selection.end,
14284                        selection.reversed,
14285                        replace_newest,
14286                        autoscroll,
14287                        window,
14288                        cx,
14289                    );
14290                }
14291
14292                if selections.len() == 1 {
14293                    let selection = selections
14294                        .last()
14295                        .expect("ensured that there's only one selection");
14296                    let query = buffer
14297                        .text_for_range(selection.start..selection.end)
14298                        .collect::<String>();
14299                    let is_empty = query.is_empty();
14300                    let select_state = SelectNextState {
14301                        query: AhoCorasick::new(&[query])?,
14302                        wordwise: true,
14303                        done: is_empty,
14304                    };
14305                    self.select_next_state = Some(select_state);
14306                } else {
14307                    self.select_next_state = None;
14308                }
14309            } else if let Some(selected_text) = selected_text {
14310                self.select_next_state = Some(SelectNextState {
14311                    query: AhoCorasick::new(&[selected_text])?,
14312                    wordwise: false,
14313                    done: false,
14314                });
14315                self.select_next_match_internal(
14316                    display_map,
14317                    replace_newest,
14318                    autoscroll,
14319                    window,
14320                    cx,
14321                )?;
14322            }
14323        }
14324        Ok(())
14325    }
14326
14327    pub fn select_all_matches(
14328        &mut self,
14329        _action: &SelectAllMatches,
14330        window: &mut Window,
14331        cx: &mut Context<Self>,
14332    ) -> Result<()> {
14333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14334
14335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14336
14337        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14338        let Some(select_next_state) = self.select_next_state.as_mut() else {
14339            return Ok(());
14340        };
14341        if select_next_state.done {
14342            return Ok(());
14343        }
14344
14345        let mut new_selections = Vec::new();
14346
14347        let reversed = self.selections.oldest::<usize>(cx).reversed;
14348        let buffer = &display_map.buffer_snapshot;
14349        let query_matches = select_next_state
14350            .query
14351            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14352
14353        for query_match in query_matches.into_iter() {
14354            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14355            let offset_range = if reversed {
14356                query_match.end()..query_match.start()
14357            } else {
14358                query_match.start()..query_match.end()
14359            };
14360
14361            if !select_next_state.wordwise
14362                || (!buffer.is_inside_word(offset_range.start, false)
14363                    && !buffer.is_inside_word(offset_range.end, false))
14364            {
14365                new_selections.push(offset_range.start..offset_range.end);
14366            }
14367        }
14368
14369        select_next_state.done = true;
14370
14371        if new_selections.is_empty() {
14372            log::error!("bug: new_selections is empty in select_all_matches");
14373            return Ok(());
14374        }
14375
14376        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14377        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14378            selections.select_ranges(new_selections)
14379        });
14380
14381        Ok(())
14382    }
14383
14384    pub fn select_next(
14385        &mut self,
14386        action: &SelectNext,
14387        window: &mut Window,
14388        cx: &mut Context<Self>,
14389    ) -> Result<()> {
14390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14392        self.select_next_match_internal(
14393            &display_map,
14394            action.replace_newest,
14395            Some(Autoscroll::newest()),
14396            window,
14397            cx,
14398        )?;
14399        Ok(())
14400    }
14401
14402    pub fn select_previous(
14403        &mut self,
14404        action: &SelectPrevious,
14405        window: &mut Window,
14406        cx: &mut Context<Self>,
14407    ) -> Result<()> {
14408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14409        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14410        let buffer = &display_map.buffer_snapshot;
14411        let mut selections = self.selections.all::<usize>(cx);
14412        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14413            let query = &select_prev_state.query;
14414            if !select_prev_state.done {
14415                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14416                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14417                let mut next_selected_range = None;
14418                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14419                let bytes_before_last_selection =
14420                    buffer.reversed_bytes_in_range(0..last_selection.start);
14421                let bytes_after_first_selection =
14422                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14423                let query_matches = query
14424                    .stream_find_iter(bytes_before_last_selection)
14425                    .map(|result| (last_selection.start, result))
14426                    .chain(
14427                        query
14428                            .stream_find_iter(bytes_after_first_selection)
14429                            .map(|result| (buffer.len(), result)),
14430                    );
14431                for (end_offset, query_match) in query_matches {
14432                    let query_match = query_match.unwrap(); // can only fail due to I/O
14433                    let offset_range =
14434                        end_offset - query_match.end()..end_offset - query_match.start();
14435
14436                    if !select_prev_state.wordwise
14437                        || (!buffer.is_inside_word(offset_range.start, false)
14438                            && !buffer.is_inside_word(offset_range.end, false))
14439                    {
14440                        next_selected_range = Some(offset_range);
14441                        break;
14442                    }
14443                }
14444
14445                if let Some(next_selected_range) = next_selected_range {
14446                    self.select_match_ranges(
14447                        next_selected_range,
14448                        last_selection.reversed,
14449                        action.replace_newest,
14450                        Some(Autoscroll::newest()),
14451                        window,
14452                        cx,
14453                    );
14454                } else {
14455                    select_prev_state.done = true;
14456                }
14457            }
14458
14459            self.select_prev_state = Some(select_prev_state);
14460        } else {
14461            let mut only_carets = true;
14462            let mut same_text_selected = true;
14463            let mut selected_text = None;
14464
14465            let mut selections_iter = selections.iter().peekable();
14466            while let Some(selection) = selections_iter.next() {
14467                if selection.start != selection.end {
14468                    only_carets = false;
14469                }
14470
14471                if same_text_selected {
14472                    if selected_text.is_none() {
14473                        selected_text =
14474                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14475                    }
14476
14477                    if let Some(next_selection) = selections_iter.peek() {
14478                        if next_selection.range().len() == selection.range().len() {
14479                            let next_selected_text = buffer
14480                                .text_for_range(next_selection.range())
14481                                .collect::<String>();
14482                            if Some(next_selected_text) != selected_text {
14483                                same_text_selected = false;
14484                                selected_text = None;
14485                            }
14486                        } else {
14487                            same_text_selected = false;
14488                            selected_text = None;
14489                        }
14490                    }
14491                }
14492            }
14493
14494            if only_carets {
14495                for selection in &mut selections {
14496                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14497                    selection.start = word_range.start;
14498                    selection.end = word_range.end;
14499                    selection.goal = SelectionGoal::None;
14500                    selection.reversed = false;
14501                    self.select_match_ranges(
14502                        selection.start..selection.end,
14503                        selection.reversed,
14504                        action.replace_newest,
14505                        Some(Autoscroll::newest()),
14506                        window,
14507                        cx,
14508                    );
14509                }
14510                if selections.len() == 1 {
14511                    let selection = selections
14512                        .last()
14513                        .expect("ensured that there's only one selection");
14514                    let query = buffer
14515                        .text_for_range(selection.start..selection.end)
14516                        .collect::<String>();
14517                    let is_empty = query.is_empty();
14518                    let select_state = SelectNextState {
14519                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14520                        wordwise: true,
14521                        done: is_empty,
14522                    };
14523                    self.select_prev_state = Some(select_state);
14524                } else {
14525                    self.select_prev_state = None;
14526                }
14527            } else if let Some(selected_text) = selected_text {
14528                self.select_prev_state = Some(SelectNextState {
14529                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14530                    wordwise: false,
14531                    done: false,
14532                });
14533                self.select_previous(action, window, cx)?;
14534            }
14535        }
14536        Ok(())
14537    }
14538
14539    pub fn find_next_match(
14540        &mut self,
14541        _: &FindNextMatch,
14542        window: &mut Window,
14543        cx: &mut Context<Self>,
14544    ) -> Result<()> {
14545        let selections = self.selections.disjoint_anchors();
14546        match selections.first() {
14547            Some(first) if selections.len() >= 2 => {
14548                self.change_selections(Default::default(), window, cx, |s| {
14549                    s.select_ranges([first.range()]);
14550                });
14551            }
14552            _ => self.select_next(
14553                &SelectNext {
14554                    replace_newest: true,
14555                },
14556                window,
14557                cx,
14558            )?,
14559        }
14560        Ok(())
14561    }
14562
14563    pub fn find_previous_match(
14564        &mut self,
14565        _: &FindPreviousMatch,
14566        window: &mut Window,
14567        cx: &mut Context<Self>,
14568    ) -> Result<()> {
14569        let selections = self.selections.disjoint_anchors();
14570        match selections.last() {
14571            Some(last) if selections.len() >= 2 => {
14572                self.change_selections(Default::default(), window, cx, |s| {
14573                    s.select_ranges([last.range()]);
14574                });
14575            }
14576            _ => self.select_previous(
14577                &SelectPrevious {
14578                    replace_newest: true,
14579                },
14580                window,
14581                cx,
14582            )?,
14583        }
14584        Ok(())
14585    }
14586
14587    pub fn toggle_comments(
14588        &mut self,
14589        action: &ToggleComments,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        if self.read_only(cx) {
14594            return;
14595        }
14596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14597        let text_layout_details = &self.text_layout_details(window);
14598        self.transact(window, cx, |this, window, cx| {
14599            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14600            let mut edits = Vec::new();
14601            let mut selection_edit_ranges = Vec::new();
14602            let mut last_toggled_row = None;
14603            let snapshot = this.buffer.read(cx).read(cx);
14604            let empty_str: Arc<str> = Arc::default();
14605            let mut suffixes_inserted = Vec::new();
14606            let ignore_indent = action.ignore_indent;
14607
14608            fn comment_prefix_range(
14609                snapshot: &MultiBufferSnapshot,
14610                row: MultiBufferRow,
14611                comment_prefix: &str,
14612                comment_prefix_whitespace: &str,
14613                ignore_indent: bool,
14614            ) -> Range<Point> {
14615                let indent_size = if ignore_indent {
14616                    0
14617                } else {
14618                    snapshot.indent_size_for_line(row).len
14619                };
14620
14621                let start = Point::new(row.0, indent_size);
14622
14623                let mut line_bytes = snapshot
14624                    .bytes_in_range(start..snapshot.max_point())
14625                    .flatten()
14626                    .copied();
14627
14628                // If this line currently begins with the line comment prefix, then record
14629                // the range containing the prefix.
14630                if line_bytes
14631                    .by_ref()
14632                    .take(comment_prefix.len())
14633                    .eq(comment_prefix.bytes())
14634                {
14635                    // Include any whitespace that matches the comment prefix.
14636                    let matching_whitespace_len = line_bytes
14637                        .zip(comment_prefix_whitespace.bytes())
14638                        .take_while(|(a, b)| a == b)
14639                        .count() as u32;
14640                    let end = Point::new(
14641                        start.row,
14642                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14643                    );
14644                    start..end
14645                } else {
14646                    start..start
14647                }
14648            }
14649
14650            fn comment_suffix_range(
14651                snapshot: &MultiBufferSnapshot,
14652                row: MultiBufferRow,
14653                comment_suffix: &str,
14654                comment_suffix_has_leading_space: bool,
14655            ) -> Range<Point> {
14656                let end = Point::new(row.0, snapshot.line_len(row));
14657                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14658
14659                let mut line_end_bytes = snapshot
14660                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14661                    .flatten()
14662                    .copied();
14663
14664                let leading_space_len = if suffix_start_column > 0
14665                    && line_end_bytes.next() == Some(b' ')
14666                    && comment_suffix_has_leading_space
14667                {
14668                    1
14669                } else {
14670                    0
14671                };
14672
14673                // If this line currently begins with the line comment prefix, then record
14674                // the range containing the prefix.
14675                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14676                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14677                    start..end
14678                } else {
14679                    end..end
14680                }
14681            }
14682
14683            // TODO: Handle selections that cross excerpts
14684            for selection in &mut selections {
14685                let start_column = snapshot
14686                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14687                    .len;
14688                let language = if let Some(language) =
14689                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14690                {
14691                    language
14692                } else {
14693                    continue;
14694                };
14695
14696                selection_edit_ranges.clear();
14697
14698                // If multiple selections contain a given row, avoid processing that
14699                // row more than once.
14700                let mut start_row = MultiBufferRow(selection.start.row);
14701                if last_toggled_row == Some(start_row) {
14702                    start_row = start_row.next_row();
14703                }
14704                let end_row =
14705                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14706                        MultiBufferRow(selection.end.row - 1)
14707                    } else {
14708                        MultiBufferRow(selection.end.row)
14709                    };
14710                last_toggled_row = Some(end_row);
14711
14712                if start_row > end_row {
14713                    continue;
14714                }
14715
14716                // If the language has line comments, toggle those.
14717                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14718
14719                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14720                if ignore_indent {
14721                    full_comment_prefixes = full_comment_prefixes
14722                        .into_iter()
14723                        .map(|s| Arc::from(s.trim_end()))
14724                        .collect();
14725                }
14726
14727                if !full_comment_prefixes.is_empty() {
14728                    let first_prefix = full_comment_prefixes
14729                        .first()
14730                        .expect("prefixes is non-empty");
14731                    let prefix_trimmed_lengths = full_comment_prefixes
14732                        .iter()
14733                        .map(|p| p.trim_end_matches(' ').len())
14734                        .collect::<SmallVec<[usize; 4]>>();
14735
14736                    let mut all_selection_lines_are_comments = true;
14737
14738                    for row in start_row.0..=end_row.0 {
14739                        let row = MultiBufferRow(row);
14740                        if start_row < end_row && snapshot.is_line_blank(row) {
14741                            continue;
14742                        }
14743
14744                        let prefix_range = full_comment_prefixes
14745                            .iter()
14746                            .zip(prefix_trimmed_lengths.iter().copied())
14747                            .map(|(prefix, trimmed_prefix_len)| {
14748                                comment_prefix_range(
14749                                    snapshot.deref(),
14750                                    row,
14751                                    &prefix[..trimmed_prefix_len],
14752                                    &prefix[trimmed_prefix_len..],
14753                                    ignore_indent,
14754                                )
14755                            })
14756                            .max_by_key(|range| range.end.column - range.start.column)
14757                            .expect("prefixes is non-empty");
14758
14759                        if prefix_range.is_empty() {
14760                            all_selection_lines_are_comments = false;
14761                        }
14762
14763                        selection_edit_ranges.push(prefix_range);
14764                    }
14765
14766                    if all_selection_lines_are_comments {
14767                        edits.extend(
14768                            selection_edit_ranges
14769                                .iter()
14770                                .cloned()
14771                                .map(|range| (range, empty_str.clone())),
14772                        );
14773                    } else {
14774                        let min_column = selection_edit_ranges
14775                            .iter()
14776                            .map(|range| range.start.column)
14777                            .min()
14778                            .unwrap_or(0);
14779                        edits.extend(selection_edit_ranges.iter().map(|range| {
14780                            let position = Point::new(range.start.row, min_column);
14781                            (position..position, first_prefix.clone())
14782                        }));
14783                    }
14784                } else if let Some(BlockCommentConfig {
14785                    start: full_comment_prefix,
14786                    end: comment_suffix,
14787                    ..
14788                }) = language.block_comment()
14789                {
14790                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14791                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14792                    let prefix_range = comment_prefix_range(
14793                        snapshot.deref(),
14794                        start_row,
14795                        comment_prefix,
14796                        comment_prefix_whitespace,
14797                        ignore_indent,
14798                    );
14799                    let suffix_range = comment_suffix_range(
14800                        snapshot.deref(),
14801                        end_row,
14802                        comment_suffix.trim_start_matches(' '),
14803                        comment_suffix.starts_with(' '),
14804                    );
14805
14806                    if prefix_range.is_empty() || suffix_range.is_empty() {
14807                        edits.push((
14808                            prefix_range.start..prefix_range.start,
14809                            full_comment_prefix.clone(),
14810                        ));
14811                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14812                        suffixes_inserted.push((end_row, comment_suffix.len()));
14813                    } else {
14814                        edits.push((prefix_range, empty_str.clone()));
14815                        edits.push((suffix_range, empty_str.clone()));
14816                    }
14817                } else {
14818                    continue;
14819                }
14820            }
14821
14822            drop(snapshot);
14823            this.buffer.update(cx, |buffer, cx| {
14824                buffer.edit(edits, None, cx);
14825            });
14826
14827            // Adjust selections so that they end before any comment suffixes that
14828            // were inserted.
14829            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14830            let mut selections = this.selections.all::<Point>(cx);
14831            let snapshot = this.buffer.read(cx).read(cx);
14832            for selection in &mut selections {
14833                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14834                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14835                        Ordering::Less => {
14836                            suffixes_inserted.next();
14837                            continue;
14838                        }
14839                        Ordering::Greater => break,
14840                        Ordering::Equal => {
14841                            if selection.end.column == snapshot.line_len(row) {
14842                                if selection.is_empty() {
14843                                    selection.start.column -= suffix_len as u32;
14844                                }
14845                                selection.end.column -= suffix_len as u32;
14846                            }
14847                            break;
14848                        }
14849                    }
14850                }
14851            }
14852
14853            drop(snapshot);
14854            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14855
14856            let selections = this.selections.all::<Point>(cx);
14857            let selections_on_single_row = selections.windows(2).all(|selections| {
14858                selections[0].start.row == selections[1].start.row
14859                    && selections[0].end.row == selections[1].end.row
14860                    && selections[0].start.row == selections[0].end.row
14861            });
14862            let selections_selecting = selections
14863                .iter()
14864                .any(|selection| selection.start != selection.end);
14865            let advance_downwards = action.advance_downwards
14866                && selections_on_single_row
14867                && !selections_selecting
14868                && !matches!(this.mode, EditorMode::SingleLine);
14869
14870            if advance_downwards {
14871                let snapshot = this.buffer.read(cx).snapshot(cx);
14872
14873                this.change_selections(Default::default(), window, cx, |s| {
14874                    s.move_cursors_with(|display_snapshot, display_point, _| {
14875                        let mut point = display_point.to_point(display_snapshot);
14876                        point.row += 1;
14877                        point = snapshot.clip_point(point, Bias::Left);
14878                        let display_point = point.to_display_point(display_snapshot);
14879                        let goal = SelectionGoal::HorizontalPosition(
14880                            display_snapshot
14881                                .x_for_display_point(display_point, text_layout_details)
14882                                .into(),
14883                        );
14884                        (display_point, goal)
14885                    })
14886                });
14887            }
14888        });
14889    }
14890
14891    pub fn select_enclosing_symbol(
14892        &mut self,
14893        _: &SelectEnclosingSymbol,
14894        window: &mut Window,
14895        cx: &mut Context<Self>,
14896    ) {
14897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14898
14899        let buffer = self.buffer.read(cx).snapshot(cx);
14900        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14901
14902        fn update_selection(
14903            selection: &Selection<usize>,
14904            buffer_snap: &MultiBufferSnapshot,
14905        ) -> Option<Selection<usize>> {
14906            let cursor = selection.head();
14907            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14908            for symbol in symbols.iter().rev() {
14909                let start = symbol.range.start.to_offset(buffer_snap);
14910                let end = symbol.range.end.to_offset(buffer_snap);
14911                let new_range = start..end;
14912                if start < selection.start || end > selection.end {
14913                    return Some(Selection {
14914                        id: selection.id,
14915                        start: new_range.start,
14916                        end: new_range.end,
14917                        goal: SelectionGoal::None,
14918                        reversed: selection.reversed,
14919                    });
14920                }
14921            }
14922            None
14923        }
14924
14925        let mut selected_larger_symbol = false;
14926        let new_selections = old_selections
14927            .iter()
14928            .map(|selection| match update_selection(selection, &buffer) {
14929                Some(new_selection) => {
14930                    if new_selection.range() != selection.range() {
14931                        selected_larger_symbol = true;
14932                    }
14933                    new_selection
14934                }
14935                None => selection.clone(),
14936            })
14937            .collect::<Vec<_>>();
14938
14939        if selected_larger_symbol {
14940            self.change_selections(Default::default(), window, cx, |s| {
14941                s.select(new_selections);
14942            });
14943        }
14944    }
14945
14946    pub fn select_larger_syntax_node(
14947        &mut self,
14948        _: &SelectLargerSyntaxNode,
14949        window: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) {
14952        let Some(visible_row_count) = self.visible_row_count() else {
14953            return;
14954        };
14955        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14956        if old_selections.is_empty() {
14957            return;
14958        }
14959
14960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14961
14962        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14963        let buffer = self.buffer.read(cx).snapshot(cx);
14964
14965        let mut selected_larger_node = false;
14966        let mut new_selections = old_selections
14967            .iter()
14968            .map(|selection| {
14969                let old_range = selection.start..selection.end;
14970
14971                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14972                    // manually select word at selection
14973                    if ["string_content", "inline"].contains(&node.kind()) {
14974                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14975                        // ignore if word is already selected
14976                        if !word_range.is_empty() && old_range != word_range {
14977                            let (last_word_range, _) =
14978                                buffer.surrounding_word(old_range.end, false);
14979                            // only select word if start and end point belongs to same word
14980                            if word_range == last_word_range {
14981                                selected_larger_node = true;
14982                                return Selection {
14983                                    id: selection.id,
14984                                    start: word_range.start,
14985                                    end: word_range.end,
14986                                    goal: SelectionGoal::None,
14987                                    reversed: selection.reversed,
14988                                };
14989                            }
14990                        }
14991                    }
14992                }
14993
14994                let mut new_range = old_range.clone();
14995                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14996                {
14997                    new_range = match containing_range {
14998                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14999                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15000                    };
15001                    if !node.is_named() {
15002                        continue;
15003                    }
15004                    if !display_map.intersects_fold(new_range.start)
15005                        && !display_map.intersects_fold(new_range.end)
15006                    {
15007                        break;
15008                    }
15009                }
15010
15011                selected_larger_node |= new_range != old_range;
15012                Selection {
15013                    id: selection.id,
15014                    start: new_range.start,
15015                    end: new_range.end,
15016                    goal: SelectionGoal::None,
15017                    reversed: selection.reversed,
15018                }
15019            })
15020            .collect::<Vec<_>>();
15021
15022        if !selected_larger_node {
15023            return; // don't put this call in the history
15024        }
15025
15026        // scroll based on transformation done to the last selection created by the user
15027        let (last_old, last_new) = old_selections
15028            .last()
15029            .zip(new_selections.last().cloned())
15030            .expect("old_selections isn't empty");
15031
15032        // revert selection
15033        let is_selection_reversed = {
15034            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15035            new_selections.last_mut().expect("checked above").reversed =
15036                should_newest_selection_be_reversed;
15037            should_newest_selection_be_reversed
15038        };
15039
15040        if selected_larger_node {
15041            self.select_syntax_node_history.disable_clearing = true;
15042            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15043                s.select(new_selections.clone());
15044            });
15045            self.select_syntax_node_history.disable_clearing = false;
15046        }
15047
15048        let start_row = last_new.start.to_display_point(&display_map).row().0;
15049        let end_row = last_new.end.to_display_point(&display_map).row().0;
15050        let selection_height = end_row - start_row + 1;
15051        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15052
15053        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15054        let scroll_behavior = if fits_on_the_screen {
15055            self.request_autoscroll(Autoscroll::fit(), cx);
15056            SelectSyntaxNodeScrollBehavior::FitSelection
15057        } else if is_selection_reversed {
15058            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15059            SelectSyntaxNodeScrollBehavior::CursorTop
15060        } else {
15061            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15062            SelectSyntaxNodeScrollBehavior::CursorBottom
15063        };
15064
15065        self.select_syntax_node_history.push((
15066            old_selections,
15067            scroll_behavior,
15068            is_selection_reversed,
15069        ));
15070    }
15071
15072    pub fn select_smaller_syntax_node(
15073        &mut self,
15074        _: &SelectSmallerSyntaxNode,
15075        window: &mut Window,
15076        cx: &mut Context<Self>,
15077    ) {
15078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15079
15080        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15081            self.select_syntax_node_history.pop()
15082        {
15083            if let Some(selection) = selections.last_mut() {
15084                selection.reversed = is_selection_reversed;
15085            }
15086
15087            self.select_syntax_node_history.disable_clearing = true;
15088            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15089                s.select(selections.to_vec());
15090            });
15091            self.select_syntax_node_history.disable_clearing = false;
15092
15093            match scroll_behavior {
15094                SelectSyntaxNodeScrollBehavior::CursorTop => {
15095                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15096                }
15097                SelectSyntaxNodeScrollBehavior::FitSelection => {
15098                    self.request_autoscroll(Autoscroll::fit(), cx);
15099                }
15100                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15101                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15102                }
15103            }
15104        }
15105    }
15106
15107    pub fn unwrap_syntax_node(
15108        &mut self,
15109        _: &UnwrapSyntaxNode,
15110        window: &mut Window,
15111        cx: &mut Context<Self>,
15112    ) {
15113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15114
15115        let buffer = self.buffer.read(cx).snapshot(cx);
15116        let selections = self
15117            .selections
15118            .all::<usize>(cx)
15119            .into_iter()
15120            // subtracting the offset requires sorting
15121            .sorted_by_key(|i| i.start);
15122
15123        let full_edits = selections
15124            .into_iter()
15125            .filter_map(|selection| {
15126                // Only requires two branches once if-let-chains stabilize (#53667)
15127                let child = if !selection.is_empty() {
15128                    selection.range()
15129                } else if let Some((_, ancestor_range)) =
15130                    buffer.syntax_ancestor(selection.start..selection.end)
15131                {
15132                    match ancestor_range {
15133                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15134                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15135                    }
15136                } else {
15137                    selection.range()
15138                };
15139
15140                let mut parent = child.clone();
15141                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15142                    parent = match ancestor_range {
15143                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15144                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15145                    };
15146                    if parent.start < child.start || parent.end > child.end {
15147                        break;
15148                    }
15149                }
15150
15151                if parent == child {
15152                    return None;
15153                }
15154                let text = buffer.text_for_range(child).collect::<String>();
15155                Some((selection.id, parent, text))
15156            })
15157            .collect::<Vec<_>>();
15158
15159        self.transact(window, cx, |this, window, cx| {
15160            this.buffer.update(cx, |buffer, cx| {
15161                buffer.edit(
15162                    full_edits
15163                        .iter()
15164                        .map(|(_, p, t)| (p.clone(), t.clone()))
15165                        .collect::<Vec<_>>(),
15166                    None,
15167                    cx,
15168                );
15169            });
15170            this.change_selections(Default::default(), window, cx, |s| {
15171                let mut offset = 0;
15172                let mut selections = vec![];
15173                for (id, parent, text) in full_edits {
15174                    let start = parent.start - offset;
15175                    offset += parent.len() - text.len();
15176                    selections.push(Selection {
15177                        id,
15178                        start,
15179                        end: start + text.len(),
15180                        reversed: false,
15181                        goal: Default::default(),
15182                    });
15183                }
15184                s.select(selections);
15185            });
15186        });
15187    }
15188
15189    pub fn select_next_syntax_node(
15190        &mut self,
15191        _: &SelectNextSyntaxNode,
15192        window: &mut Window,
15193        cx: &mut Context<Self>,
15194    ) {
15195        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15196        if old_selections.is_empty() {
15197            return;
15198        }
15199
15200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15201
15202        let buffer = self.buffer.read(cx).snapshot(cx);
15203        let mut selected_sibling = false;
15204
15205        let new_selections = old_selections
15206            .iter()
15207            .map(|selection| {
15208                let old_range = selection.start..selection.end;
15209
15210                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15211                    let new_range = node.byte_range();
15212                    selected_sibling = true;
15213                    Selection {
15214                        id: selection.id,
15215                        start: new_range.start,
15216                        end: new_range.end,
15217                        goal: SelectionGoal::None,
15218                        reversed: selection.reversed,
15219                    }
15220                } else {
15221                    selection.clone()
15222                }
15223            })
15224            .collect::<Vec<_>>();
15225
15226        if selected_sibling {
15227            self.change_selections(
15228                SelectionEffects::scroll(Autoscroll::fit()),
15229                window,
15230                cx,
15231                |s| {
15232                    s.select(new_selections);
15233                },
15234            );
15235        }
15236    }
15237
15238    pub fn select_prev_syntax_node(
15239        &mut self,
15240        _: &SelectPreviousSyntaxNode,
15241        window: &mut Window,
15242        cx: &mut Context<Self>,
15243    ) {
15244        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15245        if old_selections.is_empty() {
15246            return;
15247        }
15248
15249        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15250
15251        let buffer = self.buffer.read(cx).snapshot(cx);
15252        let mut selected_sibling = false;
15253
15254        let new_selections = old_selections
15255            .iter()
15256            .map(|selection| {
15257                let old_range = selection.start..selection.end;
15258
15259                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15260                    let new_range = node.byte_range();
15261                    selected_sibling = true;
15262                    Selection {
15263                        id: selection.id,
15264                        start: new_range.start,
15265                        end: new_range.end,
15266                        goal: SelectionGoal::None,
15267                        reversed: selection.reversed,
15268                    }
15269                } else {
15270                    selection.clone()
15271                }
15272            })
15273            .collect::<Vec<_>>();
15274
15275        if selected_sibling {
15276            self.change_selections(
15277                SelectionEffects::scroll(Autoscroll::fit()),
15278                window,
15279                cx,
15280                |s| {
15281                    s.select(new_selections);
15282                },
15283            );
15284        }
15285    }
15286
15287    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15288        if !EditorSettings::get_global(cx).gutter.runnables {
15289            self.clear_tasks();
15290            return Task::ready(());
15291        }
15292        let project = self.project().map(Entity::downgrade);
15293        let task_sources = self.lsp_task_sources(cx);
15294        let multi_buffer = self.buffer.downgrade();
15295        cx.spawn_in(window, async move |editor, cx| {
15296            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15297            let Some(project) = project.and_then(|p| p.upgrade()) else {
15298                return;
15299            };
15300            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15301                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15302            }) else {
15303                return;
15304            };
15305
15306            let hide_runnables = project
15307                .update(cx, |project, _| project.is_via_collab())
15308                .unwrap_or(true);
15309            if hide_runnables {
15310                return;
15311            }
15312            let new_rows =
15313                cx.background_spawn({
15314                    let snapshot = display_snapshot.clone();
15315                    async move {
15316                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15317                    }
15318                })
15319                    .await;
15320            let Ok(lsp_tasks) =
15321                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15322            else {
15323                return;
15324            };
15325            let lsp_tasks = lsp_tasks.await;
15326
15327            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15328                lsp_tasks
15329                    .into_iter()
15330                    .flat_map(|(kind, tasks)| {
15331                        tasks.into_iter().filter_map(move |(location, task)| {
15332                            Some((kind.clone(), location?, task))
15333                        })
15334                    })
15335                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15336                        let buffer = location.target.buffer;
15337                        let buffer_snapshot = buffer.read(cx).snapshot();
15338                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15339                            |(excerpt_id, snapshot, _)| {
15340                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15341                                    display_snapshot
15342                                        .buffer_snapshot
15343                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15344                                } else {
15345                                    None
15346                                }
15347                            },
15348                        );
15349                        if let Some(offset) = offset {
15350                            let task_buffer_range =
15351                                location.target.range.to_point(&buffer_snapshot);
15352                            let context_buffer_range =
15353                                task_buffer_range.to_offset(&buffer_snapshot);
15354                            let context_range = BufferOffset(context_buffer_range.start)
15355                                ..BufferOffset(context_buffer_range.end);
15356
15357                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15358                                .or_insert_with(|| RunnableTasks {
15359                                    templates: Vec::new(),
15360                                    offset,
15361                                    column: task_buffer_range.start.column,
15362                                    extra_variables: HashMap::default(),
15363                                    context_range,
15364                                })
15365                                .templates
15366                                .push((kind, task.original_task().clone()));
15367                        }
15368
15369                        acc
15370                    })
15371            }) else {
15372                return;
15373            };
15374
15375            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15376                buffer.language_settings(cx).tasks.prefer_lsp
15377            }) else {
15378                return;
15379            };
15380
15381            let rows = Self::runnable_rows(
15382                project,
15383                display_snapshot,
15384                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15385                new_rows,
15386                cx.clone(),
15387            )
15388            .await;
15389            editor
15390                .update(cx, |editor, _| {
15391                    editor.clear_tasks();
15392                    for (key, mut value) in rows {
15393                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15394                            value.templates.extend(lsp_tasks.templates);
15395                        }
15396
15397                        editor.insert_tasks(key, value);
15398                    }
15399                    for (key, value) in lsp_tasks_by_rows {
15400                        editor.insert_tasks(key, value);
15401                    }
15402                })
15403                .ok();
15404        })
15405    }
15406    fn fetch_runnable_ranges(
15407        snapshot: &DisplaySnapshot,
15408        range: Range<Anchor>,
15409    ) -> Vec<language::RunnableRange> {
15410        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15411    }
15412
15413    fn runnable_rows(
15414        project: Entity<Project>,
15415        snapshot: DisplaySnapshot,
15416        prefer_lsp: bool,
15417        runnable_ranges: Vec<RunnableRange>,
15418        cx: AsyncWindowContext,
15419    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15420        cx.spawn(async move |cx| {
15421            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15422            for mut runnable in runnable_ranges {
15423                let Some(tasks) = cx
15424                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15425                    .ok()
15426                else {
15427                    continue;
15428                };
15429                let mut tasks = tasks.await;
15430
15431                if prefer_lsp {
15432                    tasks.retain(|(task_kind, _)| {
15433                        !matches!(task_kind, TaskSourceKind::Language { .. })
15434                    });
15435                }
15436                if tasks.is_empty() {
15437                    continue;
15438                }
15439
15440                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15441                let Some(row) = snapshot
15442                    .buffer_snapshot
15443                    .buffer_line_for_row(MultiBufferRow(point.row))
15444                    .map(|(_, range)| range.start.row)
15445                else {
15446                    continue;
15447                };
15448
15449                let context_range =
15450                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15451                runnable_rows.push((
15452                    (runnable.buffer_id, row),
15453                    RunnableTasks {
15454                        templates: tasks,
15455                        offset: snapshot
15456                            .buffer_snapshot
15457                            .anchor_before(runnable.run_range.start),
15458                        context_range,
15459                        column: point.column,
15460                        extra_variables: runnable.extra_captures,
15461                    },
15462                ));
15463            }
15464            runnable_rows
15465        })
15466    }
15467
15468    fn templates_with_tags(
15469        project: &Entity<Project>,
15470        runnable: &mut Runnable,
15471        cx: &mut App,
15472    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15473        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15474            let (worktree_id, file) = project
15475                .buffer_for_id(runnable.buffer, cx)
15476                .and_then(|buffer| buffer.read(cx).file())
15477                .map(|file| (file.worktree_id(cx), file.clone()))
15478                .unzip();
15479
15480            (
15481                project.task_store().read(cx).task_inventory().cloned(),
15482                worktree_id,
15483                file,
15484            )
15485        });
15486
15487        let tags = mem::take(&mut runnable.tags);
15488        let language = runnable.language.clone();
15489        cx.spawn(async move |cx| {
15490            let mut templates_with_tags = Vec::new();
15491            if let Some(inventory) = inventory {
15492                for RunnableTag(tag) in tags {
15493                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15494                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15495                    }) else {
15496                        return templates_with_tags;
15497                    };
15498                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15499                        move |(_, template)| {
15500                            template.tags.iter().any(|source_tag| source_tag == &tag)
15501                        },
15502                    ));
15503                }
15504            }
15505            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15506
15507            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15508                // Strongest source wins; if we have worktree tag binding, prefer that to
15509                // global and language bindings;
15510                // if we have a global binding, prefer that to language binding.
15511                let first_mismatch = templates_with_tags
15512                    .iter()
15513                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15514                if let Some(index) = first_mismatch {
15515                    templates_with_tags.truncate(index);
15516                }
15517            }
15518
15519            templates_with_tags
15520        })
15521    }
15522
15523    pub fn move_to_enclosing_bracket(
15524        &mut self,
15525        _: &MoveToEnclosingBracket,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) {
15529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15530        self.change_selections(Default::default(), window, cx, |s| {
15531            s.move_offsets_with(|snapshot, selection| {
15532                let Some(enclosing_bracket_ranges) =
15533                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15534                else {
15535                    return;
15536                };
15537
15538                let mut best_length = usize::MAX;
15539                let mut best_inside = false;
15540                let mut best_in_bracket_range = false;
15541                let mut best_destination = None;
15542                for (open, close) in enclosing_bracket_ranges {
15543                    let close = close.to_inclusive();
15544                    let length = close.end() - open.start;
15545                    let inside = selection.start >= open.end && selection.end <= *close.start();
15546                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15547                        || close.contains(&selection.head());
15548
15549                    // If best is next to a bracket and current isn't, skip
15550                    if !in_bracket_range && best_in_bracket_range {
15551                        continue;
15552                    }
15553
15554                    // Prefer smaller lengths unless best is inside and current isn't
15555                    if length > best_length && (best_inside || !inside) {
15556                        continue;
15557                    }
15558
15559                    best_length = length;
15560                    best_inside = inside;
15561                    best_in_bracket_range = in_bracket_range;
15562                    best_destination = Some(
15563                        if close.contains(&selection.start) && close.contains(&selection.end) {
15564                            if inside { open.end } else { open.start }
15565                        } else if inside {
15566                            *close.start()
15567                        } else {
15568                            *close.end()
15569                        },
15570                    );
15571                }
15572
15573                if let Some(destination) = best_destination {
15574                    selection.collapse_to(destination, SelectionGoal::None);
15575                }
15576            })
15577        });
15578    }
15579
15580    pub fn undo_selection(
15581        &mut self,
15582        _: &UndoSelection,
15583        window: &mut Window,
15584        cx: &mut Context<Self>,
15585    ) {
15586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15587        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15588            self.selection_history.mode = SelectionHistoryMode::Undoing;
15589            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15590                this.end_selection(window, cx);
15591                this.change_selections(
15592                    SelectionEffects::scroll(Autoscroll::newest()),
15593                    window,
15594                    cx,
15595                    |s| s.select_anchors(entry.selections.to_vec()),
15596                );
15597            });
15598            self.selection_history.mode = SelectionHistoryMode::Normal;
15599
15600            self.select_next_state = entry.select_next_state;
15601            self.select_prev_state = entry.select_prev_state;
15602            self.add_selections_state = entry.add_selections_state;
15603        }
15604    }
15605
15606    pub fn redo_selection(
15607        &mut self,
15608        _: &RedoSelection,
15609        window: &mut Window,
15610        cx: &mut Context<Self>,
15611    ) {
15612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15613        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15614            self.selection_history.mode = SelectionHistoryMode::Redoing;
15615            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15616                this.end_selection(window, cx);
15617                this.change_selections(
15618                    SelectionEffects::scroll(Autoscroll::newest()),
15619                    window,
15620                    cx,
15621                    |s| s.select_anchors(entry.selections.to_vec()),
15622                );
15623            });
15624            self.selection_history.mode = SelectionHistoryMode::Normal;
15625
15626            self.select_next_state = entry.select_next_state;
15627            self.select_prev_state = entry.select_prev_state;
15628            self.add_selections_state = entry.add_selections_state;
15629        }
15630    }
15631
15632    pub fn expand_excerpts(
15633        &mut self,
15634        action: &ExpandExcerpts,
15635        _: &mut Window,
15636        cx: &mut Context<Self>,
15637    ) {
15638        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15639    }
15640
15641    pub fn expand_excerpts_down(
15642        &mut self,
15643        action: &ExpandExcerptsDown,
15644        _: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) {
15647        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15648    }
15649
15650    pub fn expand_excerpts_up(
15651        &mut self,
15652        action: &ExpandExcerptsUp,
15653        _: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) {
15656        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15657    }
15658
15659    pub fn expand_excerpts_for_direction(
15660        &mut self,
15661        lines: u32,
15662        direction: ExpandExcerptDirection,
15663
15664        cx: &mut Context<Self>,
15665    ) {
15666        let selections = self.selections.disjoint_anchors();
15667
15668        let lines = if lines == 0 {
15669            EditorSettings::get_global(cx).expand_excerpt_lines
15670        } else {
15671            lines
15672        };
15673
15674        self.buffer.update(cx, |buffer, cx| {
15675            let snapshot = buffer.snapshot(cx);
15676            let mut excerpt_ids = selections
15677                .iter()
15678                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15679                .collect::<Vec<_>>();
15680            excerpt_ids.sort();
15681            excerpt_ids.dedup();
15682            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15683        })
15684    }
15685
15686    pub fn expand_excerpt(
15687        &mut self,
15688        excerpt: ExcerptId,
15689        direction: ExpandExcerptDirection,
15690        window: &mut Window,
15691        cx: &mut Context<Self>,
15692    ) {
15693        let current_scroll_position = self.scroll_position(cx);
15694        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15695        let mut should_scroll_up = false;
15696
15697        if direction == ExpandExcerptDirection::Down {
15698            let multi_buffer = self.buffer.read(cx);
15699            let snapshot = multi_buffer.snapshot(cx);
15700            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15701                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15702                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15703            {
15704                let buffer_snapshot = buffer.read(cx).snapshot();
15705                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15706                let last_row = buffer_snapshot.max_point().row;
15707                let lines_below = last_row.saturating_sub(excerpt_end_row);
15708                should_scroll_up = lines_below >= lines_to_expand;
15709            }
15710        }
15711
15712        self.buffer.update(cx, |buffer, cx| {
15713            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15714        });
15715
15716        if should_scroll_up {
15717            let new_scroll_position =
15718                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15719            self.set_scroll_position(new_scroll_position, window, cx);
15720        }
15721    }
15722
15723    pub fn go_to_singleton_buffer_point(
15724        &mut self,
15725        point: Point,
15726        window: &mut Window,
15727        cx: &mut Context<Self>,
15728    ) {
15729        self.go_to_singleton_buffer_range(point..point, window, cx);
15730    }
15731
15732    pub fn go_to_singleton_buffer_range(
15733        &mut self,
15734        range: Range<Point>,
15735        window: &mut Window,
15736        cx: &mut Context<Self>,
15737    ) {
15738        let multibuffer = self.buffer().read(cx);
15739        let Some(buffer) = multibuffer.as_singleton() else {
15740            return;
15741        };
15742        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15743            return;
15744        };
15745        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15746            return;
15747        };
15748        self.change_selections(
15749            SelectionEffects::default().nav_history(true),
15750            window,
15751            cx,
15752            |s| s.select_anchor_ranges([start..end]),
15753        );
15754    }
15755
15756    pub fn go_to_diagnostic(
15757        &mut self,
15758        action: &GoToDiagnostic,
15759        window: &mut Window,
15760        cx: &mut Context<Self>,
15761    ) {
15762        if !self.diagnostics_enabled() {
15763            return;
15764        }
15765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15766        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15767    }
15768
15769    pub fn go_to_prev_diagnostic(
15770        &mut self,
15771        action: &GoToPreviousDiagnostic,
15772        window: &mut Window,
15773        cx: &mut Context<Self>,
15774    ) {
15775        if !self.diagnostics_enabled() {
15776            return;
15777        }
15778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15779        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15780    }
15781
15782    pub fn go_to_diagnostic_impl(
15783        &mut self,
15784        direction: Direction,
15785        severity: GoToDiagnosticSeverityFilter,
15786        window: &mut Window,
15787        cx: &mut Context<Self>,
15788    ) {
15789        let buffer = self.buffer.read(cx).snapshot(cx);
15790        let selection = self.selections.newest::<usize>(cx);
15791
15792        let mut active_group_id = None;
15793        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15794            && active_group.active_range.start.to_offset(&buffer) == selection.start
15795        {
15796            active_group_id = Some(active_group.group_id);
15797        }
15798
15799        fn filtered(
15800            snapshot: EditorSnapshot,
15801            severity: GoToDiagnosticSeverityFilter,
15802            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15803        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15804            diagnostics
15805                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15806                .filter(|entry| entry.range.start != entry.range.end)
15807                .filter(|entry| !entry.diagnostic.is_unnecessary)
15808                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15809        }
15810
15811        let snapshot = self.snapshot(window, cx);
15812        let before = filtered(
15813            snapshot.clone(),
15814            severity,
15815            buffer
15816                .diagnostics_in_range(0..selection.start)
15817                .filter(|entry| entry.range.start <= selection.start),
15818        );
15819        let after = filtered(
15820            snapshot,
15821            severity,
15822            buffer
15823                .diagnostics_in_range(selection.start..buffer.len())
15824                .filter(|entry| entry.range.start >= selection.start),
15825        );
15826
15827        let mut found: Option<DiagnosticEntry<usize>> = None;
15828        if direction == Direction::Prev {
15829            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15830            {
15831                for diagnostic in prev_diagnostics.into_iter().rev() {
15832                    if diagnostic.range.start != selection.start
15833                        || active_group_id
15834                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15835                    {
15836                        found = Some(diagnostic);
15837                        break 'outer;
15838                    }
15839                }
15840            }
15841        } else {
15842            for diagnostic in after.chain(before) {
15843                if diagnostic.range.start != selection.start
15844                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15845                {
15846                    found = Some(diagnostic);
15847                    break;
15848                }
15849            }
15850        }
15851        let Some(next_diagnostic) = found else {
15852            return;
15853        };
15854
15855        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15856        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15857            return;
15858        };
15859        self.change_selections(Default::default(), window, cx, |s| {
15860            s.select_ranges(vec![
15861                next_diagnostic.range.start..next_diagnostic.range.start,
15862            ])
15863        });
15864        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15865        self.refresh_edit_prediction(false, true, window, cx);
15866    }
15867
15868    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15870        let snapshot = self.snapshot(window, cx);
15871        let selection = self.selections.newest::<Point>(cx);
15872        self.go_to_hunk_before_or_after_position(
15873            &snapshot,
15874            selection.head(),
15875            Direction::Next,
15876            window,
15877            cx,
15878        );
15879    }
15880
15881    pub fn go_to_hunk_before_or_after_position(
15882        &mut self,
15883        snapshot: &EditorSnapshot,
15884        position: Point,
15885        direction: Direction,
15886        window: &mut Window,
15887        cx: &mut Context<Editor>,
15888    ) {
15889        let row = if direction == Direction::Next {
15890            self.hunk_after_position(snapshot, position)
15891                .map(|hunk| hunk.row_range.start)
15892        } else {
15893            self.hunk_before_position(snapshot, position)
15894        };
15895
15896        if let Some(row) = row {
15897            let destination = Point::new(row.0, 0);
15898            let autoscroll = Autoscroll::center();
15899
15900            self.unfold_ranges(&[destination..destination], false, false, cx);
15901            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15902                s.select_ranges([destination..destination]);
15903            });
15904        }
15905    }
15906
15907    fn hunk_after_position(
15908        &mut self,
15909        snapshot: &EditorSnapshot,
15910        position: Point,
15911    ) -> Option<MultiBufferDiffHunk> {
15912        snapshot
15913            .buffer_snapshot
15914            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15915            .find(|hunk| hunk.row_range.start.0 > position.row)
15916            .or_else(|| {
15917                snapshot
15918                    .buffer_snapshot
15919                    .diff_hunks_in_range(Point::zero()..position)
15920                    .find(|hunk| hunk.row_range.end.0 < position.row)
15921            })
15922    }
15923
15924    fn go_to_prev_hunk(
15925        &mut self,
15926        _: &GoToPreviousHunk,
15927        window: &mut Window,
15928        cx: &mut Context<Self>,
15929    ) {
15930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15931        let snapshot = self.snapshot(window, cx);
15932        let selection = self.selections.newest::<Point>(cx);
15933        self.go_to_hunk_before_or_after_position(
15934            &snapshot,
15935            selection.head(),
15936            Direction::Prev,
15937            window,
15938            cx,
15939        );
15940    }
15941
15942    fn hunk_before_position(
15943        &mut self,
15944        snapshot: &EditorSnapshot,
15945        position: Point,
15946    ) -> Option<MultiBufferRow> {
15947        snapshot
15948            .buffer_snapshot
15949            .diff_hunk_before(position)
15950            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15951    }
15952
15953    fn go_to_next_change(
15954        &mut self,
15955        _: &GoToNextChange,
15956        window: &mut Window,
15957        cx: &mut Context<Self>,
15958    ) {
15959        if let Some(selections) = self
15960            .change_list
15961            .next_change(1, Direction::Next)
15962            .map(|s| s.to_vec())
15963        {
15964            self.change_selections(Default::default(), window, cx, |s| {
15965                let map = s.display_map();
15966                s.select_display_ranges(selections.iter().map(|a| {
15967                    let point = a.to_display_point(&map);
15968                    point..point
15969                }))
15970            })
15971        }
15972    }
15973
15974    fn go_to_previous_change(
15975        &mut self,
15976        _: &GoToPreviousChange,
15977        window: &mut Window,
15978        cx: &mut Context<Self>,
15979    ) {
15980        if let Some(selections) = self
15981            .change_list
15982            .next_change(1, Direction::Prev)
15983            .map(|s| s.to_vec())
15984        {
15985            self.change_selections(Default::default(), window, cx, |s| {
15986                let map = s.display_map();
15987                s.select_display_ranges(selections.iter().map(|a| {
15988                    let point = a.to_display_point(&map);
15989                    point..point
15990                }))
15991            })
15992        }
15993    }
15994
15995    pub fn go_to_next_document_highlight(
15996        &mut self,
15997        _: &GoToNextDocumentHighlight,
15998        window: &mut Window,
15999        cx: &mut Context<Self>,
16000    ) {
16001        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16002    }
16003
16004    pub fn go_to_prev_document_highlight(
16005        &mut self,
16006        _: &GoToPreviousDocumentHighlight,
16007        window: &mut Window,
16008        cx: &mut Context<Self>,
16009    ) {
16010        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16011    }
16012
16013    pub fn go_to_document_highlight_before_or_after_position(
16014        &mut self,
16015        direction: Direction,
16016        window: &mut Window,
16017        cx: &mut Context<Editor>,
16018    ) {
16019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16020        let snapshot = self.snapshot(window, cx);
16021        let buffer = &snapshot.buffer_snapshot;
16022        let position = self.selections.newest::<Point>(cx).head();
16023        let anchor_position = buffer.anchor_after(position);
16024
16025        // Get all document highlights (both read and write)
16026        let mut all_highlights = Vec::new();
16027
16028        if let Some((_, read_highlights)) = self
16029            .background_highlights
16030            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16031        {
16032            all_highlights.extend(read_highlights.iter());
16033        }
16034
16035        if let Some((_, write_highlights)) = self
16036            .background_highlights
16037            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16038        {
16039            all_highlights.extend(write_highlights.iter());
16040        }
16041
16042        if all_highlights.is_empty() {
16043            return;
16044        }
16045
16046        // Sort highlights by position
16047        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16048
16049        let target_highlight = match direction {
16050            Direction::Next => {
16051                // Find the first highlight after the current position
16052                all_highlights
16053                    .iter()
16054                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16055            }
16056            Direction::Prev => {
16057                // Find the last highlight before the current position
16058                all_highlights
16059                    .iter()
16060                    .rev()
16061                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16062            }
16063        };
16064
16065        if let Some(highlight) = target_highlight {
16066            let destination = highlight.start.to_point(buffer);
16067            let autoscroll = Autoscroll::center();
16068
16069            self.unfold_ranges(&[destination..destination], false, false, cx);
16070            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16071                s.select_ranges([destination..destination]);
16072            });
16073        }
16074    }
16075
16076    fn go_to_line<T: 'static>(
16077        &mut self,
16078        position: Anchor,
16079        highlight_color: Option<Hsla>,
16080        window: &mut Window,
16081        cx: &mut Context<Self>,
16082    ) {
16083        let snapshot = self.snapshot(window, cx).display_snapshot;
16084        let position = position.to_point(&snapshot.buffer_snapshot);
16085        let start = snapshot
16086            .buffer_snapshot
16087            .clip_point(Point::new(position.row, 0), Bias::Left);
16088        let end = start + Point::new(1, 0);
16089        let start = snapshot.buffer_snapshot.anchor_before(start);
16090        let end = snapshot.buffer_snapshot.anchor_before(end);
16091
16092        self.highlight_rows::<T>(
16093            start..end,
16094            highlight_color
16095                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16096            Default::default(),
16097            cx,
16098        );
16099
16100        if self.buffer.read(cx).is_singleton() {
16101            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16102        }
16103    }
16104
16105    pub fn go_to_definition(
16106        &mut self,
16107        _: &GoToDefinition,
16108        window: &mut Window,
16109        cx: &mut Context<Self>,
16110    ) -> Task<Result<Navigated>> {
16111        let definition =
16112            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16113        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16114        cx.spawn_in(window, async move |editor, cx| {
16115            if definition.await? == Navigated::Yes {
16116                return Ok(Navigated::Yes);
16117            }
16118            match fallback_strategy {
16119                GoToDefinitionFallback::None => Ok(Navigated::No),
16120                GoToDefinitionFallback::FindAllReferences => {
16121                    match editor.update_in(cx, |editor, window, cx| {
16122                        editor.find_all_references(&FindAllReferences, window, cx)
16123                    })? {
16124                        Some(references) => references.await,
16125                        None => Ok(Navigated::No),
16126                    }
16127                }
16128            }
16129        })
16130    }
16131
16132    pub fn go_to_declaration(
16133        &mut self,
16134        _: &GoToDeclaration,
16135        window: &mut Window,
16136        cx: &mut Context<Self>,
16137    ) -> Task<Result<Navigated>> {
16138        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16139    }
16140
16141    pub fn go_to_declaration_split(
16142        &mut self,
16143        _: &GoToDeclaration,
16144        window: &mut Window,
16145        cx: &mut Context<Self>,
16146    ) -> Task<Result<Navigated>> {
16147        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16148    }
16149
16150    pub fn go_to_implementation(
16151        &mut self,
16152        _: &GoToImplementation,
16153        window: &mut Window,
16154        cx: &mut Context<Self>,
16155    ) -> Task<Result<Navigated>> {
16156        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16157    }
16158
16159    pub fn go_to_implementation_split(
16160        &mut self,
16161        _: &GoToImplementationSplit,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) -> Task<Result<Navigated>> {
16165        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16166    }
16167
16168    pub fn go_to_type_definition(
16169        &mut self,
16170        _: &GoToTypeDefinition,
16171        window: &mut Window,
16172        cx: &mut Context<Self>,
16173    ) -> Task<Result<Navigated>> {
16174        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16175    }
16176
16177    pub fn go_to_definition_split(
16178        &mut self,
16179        _: &GoToDefinitionSplit,
16180        window: &mut Window,
16181        cx: &mut Context<Self>,
16182    ) -> Task<Result<Navigated>> {
16183        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16184    }
16185
16186    pub fn go_to_type_definition_split(
16187        &mut self,
16188        _: &GoToTypeDefinitionSplit,
16189        window: &mut Window,
16190        cx: &mut Context<Self>,
16191    ) -> Task<Result<Navigated>> {
16192        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16193    }
16194
16195    fn go_to_definition_of_kind(
16196        &mut self,
16197        kind: GotoDefinitionKind,
16198        split: bool,
16199        window: &mut Window,
16200        cx: &mut Context<Self>,
16201    ) -> Task<Result<Navigated>> {
16202        let Some(provider) = self.semantics_provider.clone() else {
16203            return Task::ready(Ok(Navigated::No));
16204        };
16205        let head = self.selections.newest::<usize>(cx).head();
16206        let buffer = self.buffer.read(cx);
16207        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16208            return Task::ready(Ok(Navigated::No));
16209        };
16210        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16211            return Task::ready(Ok(Navigated::No));
16212        };
16213
16214        cx.spawn_in(window, async move |editor, cx| {
16215            let Some(definitions) = definitions.await? else {
16216                return Ok(Navigated::No);
16217            };
16218            let navigated = editor
16219                .update_in(cx, |editor, window, cx| {
16220                    editor.navigate_to_hover_links(
16221                        Some(kind),
16222                        definitions
16223                            .into_iter()
16224                            .filter(|location| {
16225                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16226                            })
16227                            .map(HoverLink::Text)
16228                            .collect::<Vec<_>>(),
16229                        split,
16230                        window,
16231                        cx,
16232                    )
16233                })?
16234                .await?;
16235            anyhow::Ok(navigated)
16236        })
16237    }
16238
16239    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16240        let selection = self.selections.newest_anchor();
16241        let head = selection.head();
16242        let tail = selection.tail();
16243
16244        let Some((buffer, start_position)) =
16245            self.buffer.read(cx).text_anchor_for_position(head, cx)
16246        else {
16247            return;
16248        };
16249
16250        let end_position = if head != tail {
16251            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16252                return;
16253            };
16254            Some(pos)
16255        } else {
16256            None
16257        };
16258
16259        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16260            let url = if let Some(end_pos) = end_position {
16261                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16262            } else {
16263                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16264            };
16265
16266            if let Some(url) = url {
16267                editor.update(cx, |_, cx| {
16268                    cx.open_url(&url);
16269                })
16270            } else {
16271                Ok(())
16272            }
16273        });
16274
16275        url_finder.detach();
16276    }
16277
16278    pub fn open_selected_filename(
16279        &mut self,
16280        _: &OpenSelectedFilename,
16281        window: &mut Window,
16282        cx: &mut Context<Self>,
16283    ) {
16284        let Some(workspace) = self.workspace() else {
16285            return;
16286        };
16287
16288        let position = self.selections.newest_anchor().head();
16289
16290        let Some((buffer, buffer_position)) =
16291            self.buffer.read(cx).text_anchor_for_position(position, cx)
16292        else {
16293            return;
16294        };
16295
16296        let project = self.project.clone();
16297
16298        cx.spawn_in(window, async move |_, cx| {
16299            let result = find_file(&buffer, project, buffer_position, cx).await;
16300
16301            if let Some((_, path)) = result {
16302                workspace
16303                    .update_in(cx, |workspace, window, cx| {
16304                        workspace.open_resolved_path(path, window, cx)
16305                    })?
16306                    .await?;
16307            }
16308            anyhow::Ok(())
16309        })
16310        .detach();
16311    }
16312
16313    pub(crate) fn navigate_to_hover_links(
16314        &mut self,
16315        kind: Option<GotoDefinitionKind>,
16316        definitions: Vec<HoverLink>,
16317        split: bool,
16318        window: &mut Window,
16319        cx: &mut Context<Editor>,
16320    ) -> Task<Result<Navigated>> {
16321        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16322        let mut first_url_or_file = None;
16323        let definitions: Vec<_> = definitions
16324            .into_iter()
16325            .filter_map(|def| match def {
16326                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16327                HoverLink::InlayHint(lsp_location, server_id) => {
16328                    let computation =
16329                        self.compute_target_location(lsp_location, server_id, window, cx);
16330                    Some(cx.background_spawn(computation))
16331                }
16332                HoverLink::Url(url) => {
16333                    first_url_or_file = Some(Either::Left(url));
16334                    None
16335                }
16336                HoverLink::File(path) => {
16337                    first_url_or_file = Some(Either::Right(path));
16338                    None
16339                }
16340            })
16341            .collect();
16342
16343        let workspace = self.workspace();
16344
16345        cx.spawn_in(window, async move |editor, acx| {
16346            let mut locations: Vec<Location> = future::join_all(definitions)
16347                .await
16348                .into_iter()
16349                .filter_map(|location| location.transpose())
16350                .collect::<Result<_>>()
16351                .context("location tasks")?;
16352
16353            if locations.len() > 1 {
16354                let Some(workspace) = workspace else {
16355                    return Ok(Navigated::No);
16356                };
16357
16358                let tab_kind = match kind {
16359                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16360                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16361                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16362                    Some(GotoDefinitionKind::Type) => "Types",
16363                };
16364                let title = editor
16365                    .update_in(acx, |_, _, cx| {
16366                        let target = locations
16367                            .iter()
16368                            .map(|location| {
16369                                location
16370                                    .buffer
16371                                    .read(cx)
16372                                    .text_for_range(location.range.clone())
16373                                    .collect::<String>()
16374                            })
16375                            .filter(|text| !text.contains('\n'))
16376                            .unique()
16377                            .take(3)
16378                            .join(", ");
16379                        if target.is_empty() {
16380                            tab_kind.to_owned()
16381                        } else {
16382                            format!("{tab_kind} for {target}")
16383                        }
16384                    })
16385                    .context("buffer title")?;
16386
16387                let opened = workspace
16388                    .update_in(acx, |workspace, window, cx| {
16389                        Self::open_locations_in_multibuffer(
16390                            workspace,
16391                            locations,
16392                            title,
16393                            split,
16394                            MultibufferSelectionMode::First,
16395                            window,
16396                            cx,
16397                        )
16398                    })
16399                    .is_ok();
16400
16401                anyhow::Ok(Navigated::from_bool(opened))
16402            } else if locations.is_empty() {
16403                // If there is one url or file, open it directly
16404                match first_url_or_file {
16405                    Some(Either::Left(url)) => {
16406                        acx.update(|_, cx| cx.open_url(&url))?;
16407                        Ok(Navigated::Yes)
16408                    }
16409                    Some(Either::Right(path)) => {
16410                        let Some(workspace) = workspace else {
16411                            return Ok(Navigated::No);
16412                        };
16413
16414                        workspace
16415                            .update_in(acx, |workspace, window, cx| {
16416                                workspace.open_resolved_path(path, window, cx)
16417                            })?
16418                            .await?;
16419                        Ok(Navigated::Yes)
16420                    }
16421                    None => Ok(Navigated::No),
16422                }
16423            } else {
16424                let Some(workspace) = workspace else {
16425                    return Ok(Navigated::No);
16426                };
16427
16428                let target = locations.pop().unwrap();
16429                editor.update_in(acx, |editor, window, cx| {
16430                    let range = target.range.to_point(target.buffer.read(cx));
16431                    let range = editor.range_for_match(&range);
16432                    let range = collapse_multiline_range(range);
16433
16434                    if !split
16435                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16436                    {
16437                        editor.go_to_singleton_buffer_range(range, window, cx);
16438                    } else {
16439                        let pane = workspace.read(cx).active_pane().clone();
16440                        window.defer(cx, move |window, cx| {
16441                            let target_editor: Entity<Self> =
16442                                workspace.update(cx, |workspace, cx| {
16443                                    let pane = if split {
16444                                        workspace.adjacent_pane(window, cx)
16445                                    } else {
16446                                        workspace.active_pane().clone()
16447                                    };
16448
16449                                    workspace.open_project_item(
16450                                        pane,
16451                                        target.buffer.clone(),
16452                                        true,
16453                                        true,
16454                                        window,
16455                                        cx,
16456                                    )
16457                                });
16458                            target_editor.update(cx, |target_editor, cx| {
16459                                // When selecting a definition in a different buffer, disable the nav history
16460                                // to avoid creating a history entry at the previous cursor location.
16461                                pane.update(cx, |pane, _| pane.disable_history());
16462                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16463                                pane.update(cx, |pane, _| pane.enable_history());
16464                            });
16465                        });
16466                    }
16467                    Navigated::Yes
16468                })
16469            }
16470        })
16471    }
16472
16473    fn compute_target_location(
16474        &self,
16475        lsp_location: lsp::Location,
16476        server_id: LanguageServerId,
16477        window: &mut Window,
16478        cx: &mut Context<Self>,
16479    ) -> Task<anyhow::Result<Option<Location>>> {
16480        let Some(project) = self.project.clone() else {
16481            return Task::ready(Ok(None));
16482        };
16483
16484        cx.spawn_in(window, async move |editor, cx| {
16485            let location_task = editor.update(cx, |_, cx| {
16486                project.update(cx, |project, cx| {
16487                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16488                })
16489            })?;
16490            let location = Some({
16491                let target_buffer_handle = location_task.await.context("open local buffer")?;
16492                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16493                    let target_start = target_buffer
16494                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16495                    let target_end = target_buffer
16496                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16497                    target_buffer.anchor_after(target_start)
16498                        ..target_buffer.anchor_before(target_end)
16499                })?;
16500                Location {
16501                    buffer: target_buffer_handle,
16502                    range,
16503                }
16504            });
16505            Ok(location)
16506        })
16507    }
16508
16509    pub fn find_all_references(
16510        &mut self,
16511        _: &FindAllReferences,
16512        window: &mut Window,
16513        cx: &mut Context<Self>,
16514    ) -> Option<Task<Result<Navigated>>> {
16515        let selection = self.selections.newest::<usize>(cx);
16516        let multi_buffer = self.buffer.read(cx);
16517        let head = selection.head();
16518
16519        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16520        let head_anchor = multi_buffer_snapshot.anchor_at(
16521            head,
16522            if head < selection.tail() {
16523                Bias::Right
16524            } else {
16525                Bias::Left
16526            },
16527        );
16528
16529        match self
16530            .find_all_references_task_sources
16531            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16532        {
16533            Ok(_) => {
16534                log::info!(
16535                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16536                );
16537                return None;
16538            }
16539            Err(i) => {
16540                self.find_all_references_task_sources.insert(i, head_anchor);
16541            }
16542        }
16543
16544        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16545        let workspace = self.workspace()?;
16546        let project = workspace.read(cx).project().clone();
16547        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16548        Some(cx.spawn_in(window, async move |editor, cx| {
16549            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16550                if let Ok(i) = editor
16551                    .find_all_references_task_sources
16552                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16553                {
16554                    editor.find_all_references_task_sources.remove(i);
16555                }
16556            });
16557
16558            let Some(locations) = references.await? else {
16559                return anyhow::Ok(Navigated::No);
16560            };
16561            if locations.is_empty() {
16562                return anyhow::Ok(Navigated::No);
16563            }
16564
16565            workspace.update_in(cx, |workspace, window, cx| {
16566                let target = locations
16567                    .iter()
16568                    .map(|location| {
16569                        location
16570                            .buffer
16571                            .read(cx)
16572                            .text_for_range(location.range.clone())
16573                            .collect::<String>()
16574                    })
16575                    .filter(|text| !text.contains('\n'))
16576                    .unique()
16577                    .take(3)
16578                    .join(", ");
16579                let title = if target.is_empty() {
16580                    "References".to_owned()
16581                } else {
16582                    format!("References to {target}")
16583                };
16584                Self::open_locations_in_multibuffer(
16585                    workspace,
16586                    locations,
16587                    title,
16588                    false,
16589                    MultibufferSelectionMode::First,
16590                    window,
16591                    cx,
16592                );
16593                Navigated::Yes
16594            })
16595        }))
16596    }
16597
16598    /// Opens a multibuffer with the given project locations in it
16599    pub fn open_locations_in_multibuffer(
16600        workspace: &mut Workspace,
16601        mut locations: Vec<Location>,
16602        title: String,
16603        split: bool,
16604        multibuffer_selection_mode: MultibufferSelectionMode,
16605        window: &mut Window,
16606        cx: &mut Context<Workspace>,
16607    ) {
16608        if locations.is_empty() {
16609            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16610            return;
16611        }
16612
16613        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16614
16615        let mut locations = locations.into_iter().peekable();
16616        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16617        let capability = workspace.project().read(cx).capability();
16618
16619        // a key to find existing multibuffer editors with the same set of locations
16620        // to prevent us from opening more and more multibuffer tabs for searches and the like
16621        let mut key = (title.clone(), vec![]);
16622        let excerpt_buffer = cx.new(|cx| {
16623            let key = &mut key.1;
16624            let mut multibuffer = MultiBuffer::new(capability);
16625            while let Some(location) = locations.next() {
16626                let buffer = location.buffer.read(cx);
16627                let mut ranges_for_buffer = Vec::new();
16628                let range = location.range.to_point(buffer);
16629                ranges_for_buffer.push(range.clone());
16630
16631                while let Some(next_location) =
16632                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16633                {
16634                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16635                }
16636
16637                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16638                key.push((
16639                    location.buffer.read(cx).remote_id(),
16640                    ranges_for_buffer.clone(),
16641                ));
16642                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16643                    PathKey::for_buffer(&location.buffer, cx),
16644                    location.buffer.clone(),
16645                    ranges_for_buffer,
16646                    multibuffer_context_lines(cx),
16647                    cx,
16648                );
16649                ranges.extend(new_ranges)
16650            }
16651
16652            multibuffer.with_title(title)
16653        });
16654        let existing = workspace.active_pane().update(cx, |pane, cx| {
16655            pane.items()
16656                .filter_map(|item| item.downcast::<Editor>())
16657                .find(|editor| {
16658                    editor
16659                        .read(cx)
16660                        .lookup_key
16661                        .as_ref()
16662                        .and_then(|it| {
16663                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16664                        })
16665                        .is_some_and(|it| *it == key)
16666                })
16667        });
16668        let editor = existing.unwrap_or_else(|| {
16669            cx.new(|cx| {
16670                let mut editor = Editor::for_multibuffer(
16671                    excerpt_buffer,
16672                    Some(workspace.project().clone()),
16673                    window,
16674                    cx,
16675                );
16676                editor.lookup_key = Some(Box::new(key));
16677                editor
16678            })
16679        });
16680        editor.update(cx, |editor, cx| {
16681            match multibuffer_selection_mode {
16682                MultibufferSelectionMode::First => {
16683                    if let Some(first_range) = ranges.first() {
16684                        editor.change_selections(
16685                            SelectionEffects::no_scroll(),
16686                            window,
16687                            cx,
16688                            |selections| {
16689                                selections.clear_disjoint();
16690                                selections
16691                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16692                            },
16693                        );
16694                    }
16695                    editor.highlight_background::<Self>(
16696                        &ranges,
16697                        |theme| theme.colors().editor_highlighted_line_background,
16698                        cx,
16699                    );
16700                }
16701                MultibufferSelectionMode::All => {
16702                    editor.change_selections(
16703                        SelectionEffects::no_scroll(),
16704                        window,
16705                        cx,
16706                        |selections| {
16707                            selections.clear_disjoint();
16708                            selections.select_anchor_ranges(ranges);
16709                        },
16710                    );
16711                }
16712            }
16713            editor.register_buffers_with_language_servers(cx);
16714        });
16715
16716        let item = Box::new(editor);
16717        let item_id = item.item_id();
16718
16719        if split {
16720            workspace.split_item(SplitDirection::Right, item, window, cx);
16721        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16722            let (preview_item_id, preview_item_idx) =
16723                workspace.active_pane().read_with(cx, |pane, _| {
16724                    (pane.preview_item_id(), pane.preview_item_idx())
16725                });
16726
16727            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16728
16729            if let Some(preview_item_id) = preview_item_id {
16730                workspace.active_pane().update(cx, |pane, cx| {
16731                    pane.remove_item(preview_item_id, false, false, window, cx);
16732                });
16733            }
16734        } else {
16735            workspace.add_item_to_active_pane(item, None, true, window, cx);
16736        }
16737        workspace.active_pane().update(cx, |pane, cx| {
16738            pane.set_preview_item_id(Some(item_id), cx);
16739        });
16740    }
16741
16742    pub fn rename(
16743        &mut self,
16744        _: &Rename,
16745        window: &mut Window,
16746        cx: &mut Context<Self>,
16747    ) -> Option<Task<Result<()>>> {
16748        use language::ToOffset as _;
16749
16750        let provider = self.semantics_provider.clone()?;
16751        let selection = self.selections.newest_anchor().clone();
16752        let (cursor_buffer, cursor_buffer_position) = self
16753            .buffer
16754            .read(cx)
16755            .text_anchor_for_position(selection.head(), cx)?;
16756        let (tail_buffer, cursor_buffer_position_end) = self
16757            .buffer
16758            .read(cx)
16759            .text_anchor_for_position(selection.tail(), cx)?;
16760        if tail_buffer != cursor_buffer {
16761            return None;
16762        }
16763
16764        let snapshot = cursor_buffer.read(cx).snapshot();
16765        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16766        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16767        let prepare_rename = provider
16768            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16769            .unwrap_or_else(|| Task::ready(Ok(None)));
16770        drop(snapshot);
16771
16772        Some(cx.spawn_in(window, async move |this, cx| {
16773            let rename_range = if let Some(range) = prepare_rename.await? {
16774                Some(range)
16775            } else {
16776                this.update(cx, |this, cx| {
16777                    let buffer = this.buffer.read(cx).snapshot(cx);
16778                    let mut buffer_highlights = this
16779                        .document_highlights_for_position(selection.head(), &buffer)
16780                        .filter(|highlight| {
16781                            highlight.start.excerpt_id == selection.head().excerpt_id
16782                                && highlight.end.excerpt_id == selection.head().excerpt_id
16783                        });
16784                    buffer_highlights
16785                        .next()
16786                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16787                })?
16788            };
16789            if let Some(rename_range) = rename_range {
16790                this.update_in(cx, |this, window, cx| {
16791                    let snapshot = cursor_buffer.read(cx).snapshot();
16792                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16793                    let cursor_offset_in_rename_range =
16794                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16795                    let cursor_offset_in_rename_range_end =
16796                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16797
16798                    this.take_rename(false, window, cx);
16799                    let buffer = this.buffer.read(cx).read(cx);
16800                    let cursor_offset = selection.head().to_offset(&buffer);
16801                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16802                    let rename_end = rename_start + rename_buffer_range.len();
16803                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16804                    let mut old_highlight_id = None;
16805                    let old_name: Arc<str> = buffer
16806                        .chunks(rename_start..rename_end, true)
16807                        .map(|chunk| {
16808                            if old_highlight_id.is_none() {
16809                                old_highlight_id = chunk.syntax_highlight_id;
16810                            }
16811                            chunk.text
16812                        })
16813                        .collect::<String>()
16814                        .into();
16815
16816                    drop(buffer);
16817
16818                    // Position the selection in the rename editor so that it matches the current selection.
16819                    this.show_local_selections = false;
16820                    let rename_editor = cx.new(|cx| {
16821                        let mut editor = Editor::single_line(window, cx);
16822                        editor.buffer.update(cx, |buffer, cx| {
16823                            buffer.edit([(0..0, old_name.clone())], None, cx)
16824                        });
16825                        let rename_selection_range = match cursor_offset_in_rename_range
16826                            .cmp(&cursor_offset_in_rename_range_end)
16827                        {
16828                            Ordering::Equal => {
16829                                editor.select_all(&SelectAll, window, cx);
16830                                return editor;
16831                            }
16832                            Ordering::Less => {
16833                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16834                            }
16835                            Ordering::Greater => {
16836                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16837                            }
16838                        };
16839                        if rename_selection_range.end > old_name.len() {
16840                            editor.select_all(&SelectAll, window, cx);
16841                        } else {
16842                            editor.change_selections(Default::default(), window, cx, |s| {
16843                                s.select_ranges([rename_selection_range]);
16844                            });
16845                        }
16846                        editor
16847                    });
16848                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16849                        if e == &EditorEvent::Focused {
16850                            cx.emit(EditorEvent::FocusedIn)
16851                        }
16852                    })
16853                    .detach();
16854
16855                    let write_highlights =
16856                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16857                    let read_highlights =
16858                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16859                    let ranges = write_highlights
16860                        .iter()
16861                        .flat_map(|(_, ranges)| ranges.iter())
16862                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16863                        .cloned()
16864                        .collect();
16865
16866                    this.highlight_text::<Rename>(
16867                        ranges,
16868                        HighlightStyle {
16869                            fade_out: Some(0.6),
16870                            ..Default::default()
16871                        },
16872                        cx,
16873                    );
16874                    let rename_focus_handle = rename_editor.focus_handle(cx);
16875                    window.focus(&rename_focus_handle);
16876                    let block_id = this.insert_blocks(
16877                        [BlockProperties {
16878                            style: BlockStyle::Flex,
16879                            placement: BlockPlacement::Below(range.start),
16880                            height: Some(1),
16881                            render: Arc::new({
16882                                let rename_editor = rename_editor.clone();
16883                                move |cx: &mut BlockContext| {
16884                                    let mut text_style = cx.editor_style.text.clone();
16885                                    if let Some(highlight_style) = old_highlight_id
16886                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16887                                    {
16888                                        text_style = text_style.highlight(highlight_style);
16889                                    }
16890                                    div()
16891                                        .block_mouse_except_scroll()
16892                                        .pl(cx.anchor_x)
16893                                        .child(EditorElement::new(
16894                                            &rename_editor,
16895                                            EditorStyle {
16896                                                background: cx.theme().system().transparent,
16897                                                local_player: cx.editor_style.local_player,
16898                                                text: text_style,
16899                                                scrollbar_width: cx.editor_style.scrollbar_width,
16900                                                syntax: cx.editor_style.syntax.clone(),
16901                                                status: cx.editor_style.status.clone(),
16902                                                inlay_hints_style: HighlightStyle {
16903                                                    font_weight: Some(FontWeight::BOLD),
16904                                                    ..make_inlay_hints_style(cx.app)
16905                                                },
16906                                                edit_prediction_styles: make_suggestion_styles(
16907                                                    cx.app,
16908                                                ),
16909                                                ..EditorStyle::default()
16910                                            },
16911                                        ))
16912                                        .into_any_element()
16913                                }
16914                            }),
16915                            priority: 0,
16916                        }],
16917                        Some(Autoscroll::fit()),
16918                        cx,
16919                    )[0];
16920                    this.pending_rename = Some(RenameState {
16921                        range,
16922                        old_name,
16923                        editor: rename_editor,
16924                        block_id,
16925                    });
16926                })?;
16927            }
16928
16929            Ok(())
16930        }))
16931    }
16932
16933    pub fn confirm_rename(
16934        &mut self,
16935        _: &ConfirmRename,
16936        window: &mut Window,
16937        cx: &mut Context<Self>,
16938    ) -> Option<Task<Result<()>>> {
16939        let rename = self.take_rename(false, window, cx)?;
16940        let workspace = self.workspace()?.downgrade();
16941        let (buffer, start) = self
16942            .buffer
16943            .read(cx)
16944            .text_anchor_for_position(rename.range.start, cx)?;
16945        let (end_buffer, _) = self
16946            .buffer
16947            .read(cx)
16948            .text_anchor_for_position(rename.range.end, cx)?;
16949        if buffer != end_buffer {
16950            return None;
16951        }
16952
16953        let old_name = rename.old_name;
16954        let new_name = rename.editor.read(cx).text(cx);
16955
16956        let rename = self.semantics_provider.as_ref()?.perform_rename(
16957            &buffer,
16958            start,
16959            new_name.clone(),
16960            cx,
16961        )?;
16962
16963        Some(cx.spawn_in(window, async move |editor, cx| {
16964            let project_transaction = rename.await?;
16965            Self::open_project_transaction(
16966                &editor,
16967                workspace,
16968                project_transaction,
16969                format!("Rename: {}{}", old_name, new_name),
16970                cx,
16971            )
16972            .await?;
16973
16974            editor.update(cx, |editor, cx| {
16975                editor.refresh_document_highlights(cx);
16976            })?;
16977            Ok(())
16978        }))
16979    }
16980
16981    fn take_rename(
16982        &mut self,
16983        moving_cursor: bool,
16984        window: &mut Window,
16985        cx: &mut Context<Self>,
16986    ) -> Option<RenameState> {
16987        let rename = self.pending_rename.take()?;
16988        if rename.editor.focus_handle(cx).is_focused(window) {
16989            window.focus(&self.focus_handle);
16990        }
16991
16992        self.remove_blocks(
16993            [rename.block_id].into_iter().collect(),
16994            Some(Autoscroll::fit()),
16995            cx,
16996        );
16997        self.clear_highlights::<Rename>(cx);
16998        self.show_local_selections = true;
16999
17000        if moving_cursor {
17001            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17002                editor.selections.newest::<usize>(cx).head()
17003            });
17004
17005            // Update the selection to match the position of the selection inside
17006            // the rename editor.
17007            let snapshot = self.buffer.read(cx).read(cx);
17008            let rename_range = rename.range.to_offset(&snapshot);
17009            let cursor_in_editor = snapshot
17010                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17011                .min(rename_range.end);
17012            drop(snapshot);
17013
17014            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17015                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17016            });
17017        } else {
17018            self.refresh_document_highlights(cx);
17019        }
17020
17021        Some(rename)
17022    }
17023
17024    pub fn pending_rename(&self) -> Option<&RenameState> {
17025        self.pending_rename.as_ref()
17026    }
17027
17028    fn format(
17029        &mut self,
17030        _: &Format,
17031        window: &mut Window,
17032        cx: &mut Context<Self>,
17033    ) -> Option<Task<Result<()>>> {
17034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17035
17036        let project = match &self.project {
17037            Some(project) => project.clone(),
17038            None => return None,
17039        };
17040
17041        Some(self.perform_format(
17042            project,
17043            FormatTrigger::Manual,
17044            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17045            window,
17046            cx,
17047        ))
17048    }
17049
17050    fn format_selections(
17051        &mut self,
17052        _: &FormatSelections,
17053        window: &mut Window,
17054        cx: &mut Context<Self>,
17055    ) -> Option<Task<Result<()>>> {
17056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17057
17058        let project = match &self.project {
17059            Some(project) => project.clone(),
17060            None => return None,
17061        };
17062
17063        let ranges = self
17064            .selections
17065            .all_adjusted(cx)
17066            .into_iter()
17067            .map(|selection| selection.range())
17068            .collect_vec();
17069
17070        Some(self.perform_format(
17071            project,
17072            FormatTrigger::Manual,
17073            FormatTarget::Ranges(ranges),
17074            window,
17075            cx,
17076        ))
17077    }
17078
17079    fn perform_format(
17080        &mut self,
17081        project: Entity<Project>,
17082        trigger: FormatTrigger,
17083        target: FormatTarget,
17084        window: &mut Window,
17085        cx: &mut Context<Self>,
17086    ) -> Task<Result<()>> {
17087        let buffer = self.buffer.clone();
17088        let (buffers, target) = match target {
17089            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17090            FormatTarget::Ranges(selection_ranges) => {
17091                let multi_buffer = buffer.read(cx);
17092                let snapshot = multi_buffer.read(cx);
17093                let mut buffers = HashSet::default();
17094                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17095                    BTreeMap::new();
17096                for selection_range in selection_ranges {
17097                    for (buffer, buffer_range, _) in
17098                        snapshot.range_to_buffer_ranges(selection_range)
17099                    {
17100                        let buffer_id = buffer.remote_id();
17101                        let start = buffer.anchor_before(buffer_range.start);
17102                        let end = buffer.anchor_after(buffer_range.end);
17103                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17104                        buffer_id_to_ranges
17105                            .entry(buffer_id)
17106                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17107                            .or_insert_with(|| vec![start..end]);
17108                    }
17109                }
17110                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17111            }
17112        };
17113
17114        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17115        let selections_prev = transaction_id_prev
17116            .and_then(|transaction_id_prev| {
17117                // default to selections as they were after the last edit, if we have them,
17118                // instead of how they are now.
17119                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17120                // will take you back to where you made the last edit, instead of staying where you scrolled
17121                self.selection_history
17122                    .transaction(transaction_id_prev)
17123                    .map(|t| t.0.clone())
17124            })
17125            .unwrap_or_else(|| self.selections.disjoint_anchors());
17126
17127        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17128        let format = project.update(cx, |project, cx| {
17129            project.format(buffers, target, true, trigger, cx)
17130        });
17131
17132        cx.spawn_in(window, async move |editor, cx| {
17133            let transaction = futures::select_biased! {
17134                transaction = format.log_err().fuse() => transaction,
17135                () = timeout => {
17136                    log::warn!("timed out waiting for formatting");
17137                    None
17138                }
17139            };
17140
17141            buffer
17142                .update(cx, |buffer, cx| {
17143                    if let Some(transaction) = transaction
17144                        && !buffer.is_singleton()
17145                    {
17146                        buffer.push_transaction(&transaction.0, cx);
17147                    }
17148                    cx.notify();
17149                })
17150                .ok();
17151
17152            if let Some(transaction_id_now) =
17153                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17154            {
17155                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17156                if has_new_transaction {
17157                    _ = editor.update(cx, |editor, _| {
17158                        editor
17159                            .selection_history
17160                            .insert_transaction(transaction_id_now, selections_prev);
17161                    });
17162                }
17163            }
17164
17165            Ok(())
17166        })
17167    }
17168
17169    fn organize_imports(
17170        &mut self,
17171        _: &OrganizeImports,
17172        window: &mut Window,
17173        cx: &mut Context<Self>,
17174    ) -> Option<Task<Result<()>>> {
17175        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17176        let project = match &self.project {
17177            Some(project) => project.clone(),
17178            None => return None,
17179        };
17180        Some(self.perform_code_action_kind(
17181            project,
17182            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17183            window,
17184            cx,
17185        ))
17186    }
17187
17188    fn perform_code_action_kind(
17189        &mut self,
17190        project: Entity<Project>,
17191        kind: CodeActionKind,
17192        window: &mut Window,
17193        cx: &mut Context<Self>,
17194    ) -> Task<Result<()>> {
17195        let buffer = self.buffer.clone();
17196        let buffers = buffer.read(cx).all_buffers();
17197        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17198        let apply_action = project.update(cx, |project, cx| {
17199            project.apply_code_action_kind(buffers, kind, true, cx)
17200        });
17201        cx.spawn_in(window, async move |_, cx| {
17202            let transaction = futures::select_biased! {
17203                () = timeout => {
17204                    log::warn!("timed out waiting for executing code action");
17205                    None
17206                }
17207                transaction = apply_action.log_err().fuse() => transaction,
17208            };
17209            buffer
17210                .update(cx, |buffer, cx| {
17211                    // check if we need this
17212                    if let Some(transaction) = transaction
17213                        && !buffer.is_singleton()
17214                    {
17215                        buffer.push_transaction(&transaction.0, cx);
17216                    }
17217                    cx.notify();
17218                })
17219                .ok();
17220            Ok(())
17221        })
17222    }
17223
17224    pub fn restart_language_server(
17225        &mut self,
17226        _: &RestartLanguageServer,
17227        _: &mut Window,
17228        cx: &mut Context<Self>,
17229    ) {
17230        if let Some(project) = self.project.clone() {
17231            self.buffer.update(cx, |multi_buffer, cx| {
17232                project.update(cx, |project, cx| {
17233                    project.restart_language_servers_for_buffers(
17234                        multi_buffer.all_buffers().into_iter().collect(),
17235                        HashSet::default(),
17236                        cx,
17237                    );
17238                });
17239            })
17240        }
17241    }
17242
17243    pub fn stop_language_server(
17244        &mut self,
17245        _: &StopLanguageServer,
17246        _: &mut Window,
17247        cx: &mut Context<Self>,
17248    ) {
17249        if let Some(project) = self.project.clone() {
17250            self.buffer.update(cx, |multi_buffer, cx| {
17251                project.update(cx, |project, cx| {
17252                    project.stop_language_servers_for_buffers(
17253                        multi_buffer.all_buffers().into_iter().collect(),
17254                        HashSet::default(),
17255                        cx,
17256                    );
17257                    cx.emit(project::Event::RefreshInlayHints);
17258                });
17259            });
17260        }
17261    }
17262
17263    fn cancel_language_server_work(
17264        workspace: &mut Workspace,
17265        _: &actions::CancelLanguageServerWork,
17266        _: &mut Window,
17267        cx: &mut Context<Workspace>,
17268    ) {
17269        let project = workspace.project();
17270        let buffers = workspace
17271            .active_item(cx)
17272            .and_then(|item| item.act_as::<Editor>(cx))
17273            .map_or(HashSet::default(), |editor| {
17274                editor.read(cx).buffer.read(cx).all_buffers()
17275            });
17276        project.update(cx, |project, cx| {
17277            project.cancel_language_server_work_for_buffers(buffers, cx);
17278        });
17279    }
17280
17281    fn show_character_palette(
17282        &mut self,
17283        _: &ShowCharacterPalette,
17284        window: &mut Window,
17285        _: &mut Context<Self>,
17286    ) {
17287        window.show_character_palette();
17288    }
17289
17290    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17291        if !self.diagnostics_enabled() {
17292            return;
17293        }
17294
17295        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17296            let buffer = self.buffer.read(cx).snapshot(cx);
17297            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17298            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17299            let is_valid = buffer
17300                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17301                .any(|entry| {
17302                    entry.diagnostic.is_primary
17303                        && !entry.range.is_empty()
17304                        && entry.range.start == primary_range_start
17305                        && entry.diagnostic.message == active_diagnostics.active_message
17306                });
17307
17308            if !is_valid {
17309                self.dismiss_diagnostics(cx);
17310            }
17311        }
17312    }
17313
17314    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17315        match &self.active_diagnostics {
17316            ActiveDiagnostic::Group(group) => Some(group),
17317            _ => None,
17318        }
17319    }
17320
17321    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17322        if !self.diagnostics_enabled() {
17323            return;
17324        }
17325        self.dismiss_diagnostics(cx);
17326        self.active_diagnostics = ActiveDiagnostic::All;
17327    }
17328
17329    fn activate_diagnostics(
17330        &mut self,
17331        buffer_id: BufferId,
17332        diagnostic: DiagnosticEntry<usize>,
17333        window: &mut Window,
17334        cx: &mut Context<Self>,
17335    ) {
17336        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17337            return;
17338        }
17339        self.dismiss_diagnostics(cx);
17340        let snapshot = self.snapshot(window, cx);
17341        let buffer = self.buffer.read(cx).snapshot(cx);
17342        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17343            return;
17344        };
17345
17346        let diagnostic_group = buffer
17347            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17348            .collect::<Vec<_>>();
17349
17350        let blocks =
17351            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17352
17353        let blocks = self.display_map.update(cx, |display_map, cx| {
17354            display_map.insert_blocks(blocks, cx).into_iter().collect()
17355        });
17356        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17357            active_range: buffer.anchor_before(diagnostic.range.start)
17358                ..buffer.anchor_after(diagnostic.range.end),
17359            active_message: diagnostic.diagnostic.message.clone(),
17360            group_id: diagnostic.diagnostic.group_id,
17361            blocks,
17362        });
17363        cx.notify();
17364    }
17365
17366    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17367        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17368            return;
17369        };
17370
17371        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17372        if let ActiveDiagnostic::Group(group) = prev {
17373            self.display_map.update(cx, |display_map, cx| {
17374                display_map.remove_blocks(group.blocks, cx);
17375            });
17376            cx.notify();
17377        }
17378    }
17379
17380    /// Disable inline diagnostics rendering for this editor.
17381    pub fn disable_inline_diagnostics(&mut self) {
17382        self.inline_diagnostics_enabled = false;
17383        self.inline_diagnostics_update = Task::ready(());
17384        self.inline_diagnostics.clear();
17385    }
17386
17387    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17388        self.diagnostics_enabled = false;
17389        self.dismiss_diagnostics(cx);
17390        self.inline_diagnostics_update = Task::ready(());
17391        self.inline_diagnostics.clear();
17392    }
17393
17394    pub fn disable_word_completions(&mut self) {
17395        self.word_completions_enabled = false;
17396    }
17397
17398    pub fn diagnostics_enabled(&self) -> bool {
17399        self.diagnostics_enabled && self.mode.is_full()
17400    }
17401
17402    pub fn inline_diagnostics_enabled(&self) -> bool {
17403        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17404    }
17405
17406    pub fn show_inline_diagnostics(&self) -> bool {
17407        self.show_inline_diagnostics
17408    }
17409
17410    pub fn toggle_inline_diagnostics(
17411        &mut self,
17412        _: &ToggleInlineDiagnostics,
17413        window: &mut Window,
17414        cx: &mut Context<Editor>,
17415    ) {
17416        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17417        self.refresh_inline_diagnostics(false, window, cx);
17418    }
17419
17420    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17421        self.diagnostics_max_severity = severity;
17422        self.display_map.update(cx, |display_map, _| {
17423            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17424        });
17425    }
17426
17427    pub fn toggle_diagnostics(
17428        &mut self,
17429        _: &ToggleDiagnostics,
17430        window: &mut Window,
17431        cx: &mut Context<Editor>,
17432    ) {
17433        if !self.diagnostics_enabled() {
17434            return;
17435        }
17436
17437        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17438            EditorSettings::get_global(cx)
17439                .diagnostics_max_severity
17440                .filter(|severity| severity != &DiagnosticSeverity::Off)
17441                .unwrap_or(DiagnosticSeverity::Hint)
17442        } else {
17443            DiagnosticSeverity::Off
17444        };
17445        self.set_max_diagnostics_severity(new_severity, cx);
17446        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17447            self.active_diagnostics = ActiveDiagnostic::None;
17448            self.inline_diagnostics_update = Task::ready(());
17449            self.inline_diagnostics.clear();
17450        } else {
17451            self.refresh_inline_diagnostics(false, window, cx);
17452        }
17453
17454        cx.notify();
17455    }
17456
17457    pub fn toggle_minimap(
17458        &mut self,
17459        _: &ToggleMinimap,
17460        window: &mut Window,
17461        cx: &mut Context<Editor>,
17462    ) {
17463        if self.supports_minimap(cx) {
17464            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17465        }
17466    }
17467
17468    fn refresh_inline_diagnostics(
17469        &mut self,
17470        debounce: bool,
17471        window: &mut Window,
17472        cx: &mut Context<Self>,
17473    ) {
17474        let max_severity = ProjectSettings::get_global(cx)
17475            .diagnostics
17476            .inline
17477            .max_severity
17478            .unwrap_or(self.diagnostics_max_severity);
17479
17480        if !self.inline_diagnostics_enabled()
17481            || !self.show_inline_diagnostics
17482            || max_severity == DiagnosticSeverity::Off
17483        {
17484            self.inline_diagnostics_update = Task::ready(());
17485            self.inline_diagnostics.clear();
17486            return;
17487        }
17488
17489        let debounce_ms = ProjectSettings::get_global(cx)
17490            .diagnostics
17491            .inline
17492            .update_debounce_ms;
17493        let debounce = if debounce && debounce_ms > 0 {
17494            Some(Duration::from_millis(debounce_ms))
17495        } else {
17496            None
17497        };
17498        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17499            if let Some(debounce) = debounce {
17500                cx.background_executor().timer(debounce).await;
17501            }
17502            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17503                editor
17504                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17505                    .ok()
17506            }) else {
17507                return;
17508            };
17509
17510            let new_inline_diagnostics = cx
17511                .background_spawn(async move {
17512                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17513                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17514                        let message = diagnostic_entry
17515                            .diagnostic
17516                            .message
17517                            .split_once('\n')
17518                            .map(|(line, _)| line)
17519                            .map(SharedString::new)
17520                            .unwrap_or_else(|| {
17521                                SharedString::from(diagnostic_entry.diagnostic.message)
17522                            });
17523                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17524                        let (Ok(i) | Err(i)) = inline_diagnostics
17525                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17526                        inline_diagnostics.insert(
17527                            i,
17528                            (
17529                                start_anchor,
17530                                InlineDiagnostic {
17531                                    message,
17532                                    group_id: diagnostic_entry.diagnostic.group_id,
17533                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17534                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17535                                    severity: diagnostic_entry.diagnostic.severity,
17536                                },
17537                            ),
17538                        );
17539                    }
17540                    inline_diagnostics
17541                })
17542                .await;
17543
17544            editor
17545                .update(cx, |editor, cx| {
17546                    editor.inline_diagnostics = new_inline_diagnostics;
17547                    cx.notify();
17548                })
17549                .ok();
17550        });
17551    }
17552
17553    fn pull_diagnostics(
17554        &mut self,
17555        buffer_id: Option<BufferId>,
17556        window: &Window,
17557        cx: &mut Context<Self>,
17558    ) -> Option<()> {
17559        if !self.mode().is_full() {
17560            return None;
17561        }
17562        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17563            .diagnostics
17564            .lsp_pull_diagnostics;
17565        if !pull_diagnostics_settings.enabled {
17566            return None;
17567        }
17568        let project = self.project()?.downgrade();
17569        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17570        let mut buffers = self.buffer.read(cx).all_buffers();
17571        if let Some(buffer_id) = buffer_id {
17572            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17573        }
17574
17575        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17576            cx.background_executor().timer(debounce).await;
17577
17578            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17579                buffers
17580                    .into_iter()
17581                    .filter_map(|buffer| {
17582                        project
17583                            .update(cx, |project, cx| {
17584                                project.lsp_store().update(cx, |lsp_store, cx| {
17585                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17586                                })
17587                            })
17588                            .ok()
17589                    })
17590                    .collect::<FuturesUnordered<_>>()
17591            }) else {
17592                return;
17593            };
17594
17595            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17596                match pull_task {
17597                    Ok(()) => {
17598                        if editor
17599                            .update_in(cx, |editor, window, cx| {
17600                                editor.update_diagnostics_state(window, cx);
17601                            })
17602                            .is_err()
17603                        {
17604                            return;
17605                        }
17606                    }
17607                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17608                }
17609            }
17610        });
17611
17612        Some(())
17613    }
17614
17615    pub fn set_selections_from_remote(
17616        &mut self,
17617        selections: Vec<Selection<Anchor>>,
17618        pending_selection: Option<Selection<Anchor>>,
17619        window: &mut Window,
17620        cx: &mut Context<Self>,
17621    ) {
17622        let old_cursor_position = self.selections.newest_anchor().head();
17623        self.selections.change_with(cx, |s| {
17624            s.select_anchors(selections);
17625            if let Some(pending_selection) = pending_selection {
17626                s.set_pending(pending_selection, SelectMode::Character);
17627            } else {
17628                s.clear_pending();
17629            }
17630        });
17631        self.selections_did_change(
17632            false,
17633            &old_cursor_position,
17634            SelectionEffects::default(),
17635            window,
17636            cx,
17637        );
17638    }
17639
17640    pub fn transact(
17641        &mut self,
17642        window: &mut Window,
17643        cx: &mut Context<Self>,
17644        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17645    ) -> Option<TransactionId> {
17646        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17647            this.start_transaction_at(Instant::now(), window, cx);
17648            update(this, window, cx);
17649            this.end_transaction_at(Instant::now(), cx)
17650        })
17651    }
17652
17653    pub fn start_transaction_at(
17654        &mut self,
17655        now: Instant,
17656        window: &mut Window,
17657        cx: &mut Context<Self>,
17658    ) -> Option<TransactionId> {
17659        self.end_selection(window, cx);
17660        if let Some(tx_id) = self
17661            .buffer
17662            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17663        {
17664            self.selection_history
17665                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17666            cx.emit(EditorEvent::TransactionBegun {
17667                transaction_id: tx_id,
17668            });
17669            Some(tx_id)
17670        } else {
17671            None
17672        }
17673    }
17674
17675    pub fn end_transaction_at(
17676        &mut self,
17677        now: Instant,
17678        cx: &mut Context<Self>,
17679    ) -> Option<TransactionId> {
17680        if let Some(transaction_id) = self
17681            .buffer
17682            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17683        {
17684            if let Some((_, end_selections)) =
17685                self.selection_history.transaction_mut(transaction_id)
17686            {
17687                *end_selections = Some(self.selections.disjoint_anchors());
17688            } else {
17689                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17690            }
17691
17692            cx.emit(EditorEvent::Edited { transaction_id });
17693            Some(transaction_id)
17694        } else {
17695            None
17696        }
17697    }
17698
17699    pub fn modify_transaction_selection_history(
17700        &mut self,
17701        transaction_id: TransactionId,
17702        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17703    ) -> bool {
17704        self.selection_history
17705            .transaction_mut(transaction_id)
17706            .map(modify)
17707            .is_some()
17708    }
17709
17710    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17711        if self.selection_mark_mode {
17712            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17713                s.move_with(|_, sel| {
17714                    sel.collapse_to(sel.head(), SelectionGoal::None);
17715                });
17716            })
17717        }
17718        self.selection_mark_mode = true;
17719        cx.notify();
17720    }
17721
17722    pub fn swap_selection_ends(
17723        &mut self,
17724        _: &actions::SwapSelectionEnds,
17725        window: &mut Window,
17726        cx: &mut Context<Self>,
17727    ) {
17728        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17729            s.move_with(|_, sel| {
17730                if sel.start != sel.end {
17731                    sel.reversed = !sel.reversed
17732                }
17733            });
17734        });
17735        self.request_autoscroll(Autoscroll::newest(), cx);
17736        cx.notify();
17737    }
17738
17739    pub fn toggle_focus(
17740        workspace: &mut Workspace,
17741        _: &actions::ToggleFocus,
17742        window: &mut Window,
17743        cx: &mut Context<Workspace>,
17744    ) {
17745        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17746            return;
17747        };
17748        workspace.activate_item(&item, true, true, window, cx);
17749    }
17750
17751    pub fn toggle_fold(
17752        &mut self,
17753        _: &actions::ToggleFold,
17754        window: &mut Window,
17755        cx: &mut Context<Self>,
17756    ) {
17757        if self.is_singleton(cx) {
17758            let selection = self.selections.newest::<Point>(cx);
17759
17760            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17761            let range = if selection.is_empty() {
17762                let point = selection.head().to_display_point(&display_map);
17763                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17764                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17765                    .to_point(&display_map);
17766                start..end
17767            } else {
17768                selection.range()
17769            };
17770            if display_map.folds_in_range(range).next().is_some() {
17771                self.unfold_lines(&Default::default(), window, cx)
17772            } else {
17773                self.fold(&Default::default(), window, cx)
17774            }
17775        } else {
17776            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17777            let buffer_ids: HashSet<_> = self
17778                .selections
17779                .disjoint_anchor_ranges()
17780                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17781                .collect();
17782
17783            let should_unfold = buffer_ids
17784                .iter()
17785                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17786
17787            for buffer_id in buffer_ids {
17788                if should_unfold {
17789                    self.unfold_buffer(buffer_id, cx);
17790                } else {
17791                    self.fold_buffer(buffer_id, cx);
17792                }
17793            }
17794        }
17795    }
17796
17797    pub fn toggle_fold_recursive(
17798        &mut self,
17799        _: &actions::ToggleFoldRecursive,
17800        window: &mut Window,
17801        cx: &mut Context<Self>,
17802    ) {
17803        let selection = self.selections.newest::<Point>(cx);
17804
17805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17806        let range = if selection.is_empty() {
17807            let point = selection.head().to_display_point(&display_map);
17808            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17809            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17810                .to_point(&display_map);
17811            start..end
17812        } else {
17813            selection.range()
17814        };
17815        if display_map.folds_in_range(range).next().is_some() {
17816            self.unfold_recursive(&Default::default(), window, cx)
17817        } else {
17818            self.fold_recursive(&Default::default(), window, cx)
17819        }
17820    }
17821
17822    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17823        if self.is_singleton(cx) {
17824            let mut to_fold = Vec::new();
17825            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17826            let selections = self.selections.all_adjusted(cx);
17827
17828            for selection in selections {
17829                let range = selection.range().sorted();
17830                let buffer_start_row = range.start.row;
17831
17832                if range.start.row != range.end.row {
17833                    let mut found = false;
17834                    let mut row = range.start.row;
17835                    while row <= range.end.row {
17836                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17837                        {
17838                            found = true;
17839                            row = crease.range().end.row + 1;
17840                            to_fold.push(crease);
17841                        } else {
17842                            row += 1
17843                        }
17844                    }
17845                    if found {
17846                        continue;
17847                    }
17848                }
17849
17850                for row in (0..=range.start.row).rev() {
17851                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17852                        && crease.range().end.row >= buffer_start_row
17853                    {
17854                        to_fold.push(crease);
17855                        if row <= range.start.row {
17856                            break;
17857                        }
17858                    }
17859                }
17860            }
17861
17862            self.fold_creases(to_fold, true, window, cx);
17863        } else {
17864            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17865            let buffer_ids = self
17866                .selections
17867                .disjoint_anchor_ranges()
17868                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17869                .collect::<HashSet<_>>();
17870            for buffer_id in buffer_ids {
17871                self.fold_buffer(buffer_id, cx);
17872            }
17873        }
17874    }
17875
17876    pub fn toggle_fold_all(
17877        &mut self,
17878        _: &actions::ToggleFoldAll,
17879        window: &mut Window,
17880        cx: &mut Context<Self>,
17881    ) {
17882        if self.buffer.read(cx).is_singleton() {
17883            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17884            let has_folds = display_map
17885                .folds_in_range(0..display_map.buffer_snapshot.len())
17886                .next()
17887                .is_some();
17888
17889            if has_folds {
17890                self.unfold_all(&actions::UnfoldAll, window, cx);
17891            } else {
17892                self.fold_all(&actions::FoldAll, window, cx);
17893            }
17894        } else {
17895            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17896            let should_unfold = buffer_ids
17897                .iter()
17898                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17899
17900            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17901                editor
17902                    .update_in(cx, |editor, _, cx| {
17903                        for buffer_id in buffer_ids {
17904                            if should_unfold {
17905                                editor.unfold_buffer(buffer_id, cx);
17906                            } else {
17907                                editor.fold_buffer(buffer_id, cx);
17908                            }
17909                        }
17910                    })
17911                    .ok();
17912            });
17913        }
17914    }
17915
17916    fn fold_at_level(
17917        &mut self,
17918        fold_at: &FoldAtLevel,
17919        window: &mut Window,
17920        cx: &mut Context<Self>,
17921    ) {
17922        if !self.buffer.read(cx).is_singleton() {
17923            return;
17924        }
17925
17926        let fold_at_level = fold_at.0;
17927        let snapshot = self.buffer.read(cx).snapshot(cx);
17928        let mut to_fold = Vec::new();
17929        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17930
17931        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17932            while start_row < end_row {
17933                match self
17934                    .snapshot(window, cx)
17935                    .crease_for_buffer_row(MultiBufferRow(start_row))
17936                {
17937                    Some(crease) => {
17938                        let nested_start_row = crease.range().start.row + 1;
17939                        let nested_end_row = crease.range().end.row;
17940
17941                        if current_level < fold_at_level {
17942                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17943                        } else if current_level == fold_at_level {
17944                            to_fold.push(crease);
17945                        }
17946
17947                        start_row = nested_end_row + 1;
17948                    }
17949                    None => start_row += 1,
17950                }
17951            }
17952        }
17953
17954        self.fold_creases(to_fold, true, window, cx);
17955    }
17956
17957    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17958        if self.buffer.read(cx).is_singleton() {
17959            let mut fold_ranges = Vec::new();
17960            let snapshot = self.buffer.read(cx).snapshot(cx);
17961
17962            for row in 0..snapshot.max_row().0 {
17963                if let Some(foldable_range) = self
17964                    .snapshot(window, cx)
17965                    .crease_for_buffer_row(MultiBufferRow(row))
17966                {
17967                    fold_ranges.push(foldable_range);
17968                }
17969            }
17970
17971            self.fold_creases(fold_ranges, true, window, cx);
17972        } else {
17973            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17974                editor
17975                    .update_in(cx, |editor, _, cx| {
17976                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17977                            editor.fold_buffer(buffer_id, cx);
17978                        }
17979                    })
17980                    .ok();
17981            });
17982        }
17983    }
17984
17985    pub fn fold_function_bodies(
17986        &mut self,
17987        _: &actions::FoldFunctionBodies,
17988        window: &mut Window,
17989        cx: &mut Context<Self>,
17990    ) {
17991        let snapshot = self.buffer.read(cx).snapshot(cx);
17992
17993        let ranges = snapshot
17994            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17995            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17996            .collect::<Vec<_>>();
17997
17998        let creases = ranges
17999            .into_iter()
18000            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18001            .collect();
18002
18003        self.fold_creases(creases, true, window, cx);
18004    }
18005
18006    pub fn fold_recursive(
18007        &mut self,
18008        _: &actions::FoldRecursive,
18009        window: &mut Window,
18010        cx: &mut Context<Self>,
18011    ) {
18012        let mut to_fold = Vec::new();
18013        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18014        let selections = self.selections.all_adjusted(cx);
18015
18016        for selection in selections {
18017            let range = selection.range().sorted();
18018            let buffer_start_row = range.start.row;
18019
18020            if range.start.row != range.end.row {
18021                let mut found = false;
18022                for row in range.start.row..=range.end.row {
18023                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18024                        found = true;
18025                        to_fold.push(crease);
18026                    }
18027                }
18028                if found {
18029                    continue;
18030                }
18031            }
18032
18033            for row in (0..=range.start.row).rev() {
18034                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18035                    if crease.range().end.row >= buffer_start_row {
18036                        to_fold.push(crease);
18037                    } else {
18038                        break;
18039                    }
18040                }
18041            }
18042        }
18043
18044        self.fold_creases(to_fold, true, window, cx);
18045    }
18046
18047    pub fn fold_at(
18048        &mut self,
18049        buffer_row: MultiBufferRow,
18050        window: &mut Window,
18051        cx: &mut Context<Self>,
18052    ) {
18053        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18054
18055        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18056            let autoscroll = self
18057                .selections
18058                .all::<Point>(cx)
18059                .iter()
18060                .any(|selection| crease.range().overlaps(&selection.range()));
18061
18062            self.fold_creases(vec![crease], autoscroll, window, cx);
18063        }
18064    }
18065
18066    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18067        if self.is_singleton(cx) {
18068            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18069            let buffer = &display_map.buffer_snapshot;
18070            let selections = self.selections.all::<Point>(cx);
18071            let ranges = selections
18072                .iter()
18073                .map(|s| {
18074                    let range = s.display_range(&display_map).sorted();
18075                    let mut start = range.start.to_point(&display_map);
18076                    let mut end = range.end.to_point(&display_map);
18077                    start.column = 0;
18078                    end.column = buffer.line_len(MultiBufferRow(end.row));
18079                    start..end
18080                })
18081                .collect::<Vec<_>>();
18082
18083            self.unfold_ranges(&ranges, true, true, cx);
18084        } else {
18085            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18086            let buffer_ids = self
18087                .selections
18088                .disjoint_anchor_ranges()
18089                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18090                .collect::<HashSet<_>>();
18091            for buffer_id in buffer_ids {
18092                self.unfold_buffer(buffer_id, cx);
18093            }
18094        }
18095    }
18096
18097    pub fn unfold_recursive(
18098        &mut self,
18099        _: &UnfoldRecursive,
18100        _window: &mut Window,
18101        cx: &mut Context<Self>,
18102    ) {
18103        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18104        let selections = self.selections.all::<Point>(cx);
18105        let ranges = selections
18106            .iter()
18107            .map(|s| {
18108                let mut range = s.display_range(&display_map).sorted();
18109                *range.start.column_mut() = 0;
18110                *range.end.column_mut() = display_map.line_len(range.end.row());
18111                let start = range.start.to_point(&display_map);
18112                let end = range.end.to_point(&display_map);
18113                start..end
18114            })
18115            .collect::<Vec<_>>();
18116
18117        self.unfold_ranges(&ranges, true, true, cx);
18118    }
18119
18120    pub fn unfold_at(
18121        &mut self,
18122        buffer_row: MultiBufferRow,
18123        _window: &mut Window,
18124        cx: &mut Context<Self>,
18125    ) {
18126        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18127
18128        let intersection_range = Point::new(buffer_row.0, 0)
18129            ..Point::new(
18130                buffer_row.0,
18131                display_map.buffer_snapshot.line_len(buffer_row),
18132            );
18133
18134        let autoscroll = self
18135            .selections
18136            .all::<Point>(cx)
18137            .iter()
18138            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18139
18140        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18141    }
18142
18143    pub fn unfold_all(
18144        &mut self,
18145        _: &actions::UnfoldAll,
18146        _window: &mut Window,
18147        cx: &mut Context<Self>,
18148    ) {
18149        if self.buffer.read(cx).is_singleton() {
18150            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18151            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18152        } else {
18153            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18154                editor
18155                    .update(cx, |editor, cx| {
18156                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18157                            editor.unfold_buffer(buffer_id, cx);
18158                        }
18159                    })
18160                    .ok();
18161            });
18162        }
18163    }
18164
18165    pub fn fold_selected_ranges(
18166        &mut self,
18167        _: &FoldSelectedRanges,
18168        window: &mut Window,
18169        cx: &mut Context<Self>,
18170    ) {
18171        let selections = self.selections.all_adjusted(cx);
18172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18173        let ranges = selections
18174            .into_iter()
18175            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18176            .collect::<Vec<_>>();
18177        self.fold_creases(ranges, true, window, cx);
18178    }
18179
18180    pub fn fold_ranges<T: ToOffset + Clone>(
18181        &mut self,
18182        ranges: Vec<Range<T>>,
18183        auto_scroll: bool,
18184        window: &mut Window,
18185        cx: &mut Context<Self>,
18186    ) {
18187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18188        let ranges = ranges
18189            .into_iter()
18190            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18191            .collect::<Vec<_>>();
18192        self.fold_creases(ranges, auto_scroll, window, cx);
18193    }
18194
18195    pub fn fold_creases<T: ToOffset + Clone>(
18196        &mut self,
18197        creases: Vec<Crease<T>>,
18198        auto_scroll: bool,
18199        _window: &mut Window,
18200        cx: &mut Context<Self>,
18201    ) {
18202        if creases.is_empty() {
18203            return;
18204        }
18205
18206        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18207
18208        if auto_scroll {
18209            self.request_autoscroll(Autoscroll::fit(), cx);
18210        }
18211
18212        cx.notify();
18213
18214        self.scrollbar_marker_state.dirty = true;
18215        self.folds_did_change(cx);
18216    }
18217
18218    /// Removes any folds whose ranges intersect any of the given ranges.
18219    pub fn unfold_ranges<T: ToOffset + Clone>(
18220        &mut self,
18221        ranges: &[Range<T>],
18222        inclusive: bool,
18223        auto_scroll: bool,
18224        cx: &mut Context<Self>,
18225    ) {
18226        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18227            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18228        });
18229        self.folds_did_change(cx);
18230    }
18231
18232    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18233        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18234            return;
18235        }
18236        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18237        self.display_map.update(cx, |display_map, cx| {
18238            display_map.fold_buffers([buffer_id], cx)
18239        });
18240        cx.emit(EditorEvent::BufferFoldToggled {
18241            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18242            folded: true,
18243        });
18244        cx.notify();
18245    }
18246
18247    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18248        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18249            return;
18250        }
18251        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18252        self.display_map.update(cx, |display_map, cx| {
18253            display_map.unfold_buffers([buffer_id], cx);
18254        });
18255        cx.emit(EditorEvent::BufferFoldToggled {
18256            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18257            folded: false,
18258        });
18259        cx.notify();
18260    }
18261
18262    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18263        self.display_map.read(cx).is_buffer_folded(buffer)
18264    }
18265
18266    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18267        self.display_map.read(cx).folded_buffers()
18268    }
18269
18270    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18271        self.display_map.update(cx, |display_map, cx| {
18272            display_map.disable_header_for_buffer(buffer_id, cx);
18273        });
18274        cx.notify();
18275    }
18276
18277    /// Removes any folds with the given ranges.
18278    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18279        &mut self,
18280        ranges: &[Range<T>],
18281        type_id: TypeId,
18282        auto_scroll: bool,
18283        cx: &mut Context<Self>,
18284    ) {
18285        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18286            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18287        });
18288        self.folds_did_change(cx);
18289    }
18290
18291    fn remove_folds_with<T: ToOffset + Clone>(
18292        &mut self,
18293        ranges: &[Range<T>],
18294        auto_scroll: bool,
18295        cx: &mut Context<Self>,
18296        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18297    ) {
18298        if ranges.is_empty() {
18299            return;
18300        }
18301
18302        let mut buffers_affected = HashSet::default();
18303        let multi_buffer = self.buffer().read(cx);
18304        for range in ranges {
18305            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18306                buffers_affected.insert(buffer.read(cx).remote_id());
18307            };
18308        }
18309
18310        self.display_map.update(cx, update);
18311
18312        if auto_scroll {
18313            self.request_autoscroll(Autoscroll::fit(), cx);
18314        }
18315
18316        cx.notify();
18317        self.scrollbar_marker_state.dirty = true;
18318        self.active_indent_guides_state.dirty = true;
18319    }
18320
18321    pub fn update_renderer_widths(
18322        &mut self,
18323        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18324        cx: &mut Context<Self>,
18325    ) -> bool {
18326        self.display_map
18327            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18328    }
18329
18330    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18331        self.display_map.read(cx).fold_placeholder.clone()
18332    }
18333
18334    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18335        self.buffer.update(cx, |buffer, cx| {
18336            buffer.set_all_diff_hunks_expanded(cx);
18337        });
18338    }
18339
18340    pub fn expand_all_diff_hunks(
18341        &mut self,
18342        _: &ExpandAllDiffHunks,
18343        _window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        self.buffer.update(cx, |buffer, cx| {
18347            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18348        });
18349    }
18350
18351    pub fn toggle_selected_diff_hunks(
18352        &mut self,
18353        _: &ToggleSelectedDiffHunks,
18354        _window: &mut Window,
18355        cx: &mut Context<Self>,
18356    ) {
18357        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18358        self.toggle_diff_hunks_in_ranges(ranges, cx);
18359    }
18360
18361    pub fn diff_hunks_in_ranges<'a>(
18362        &'a self,
18363        ranges: &'a [Range<Anchor>],
18364        buffer: &'a MultiBufferSnapshot,
18365    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18366        ranges.iter().flat_map(move |range| {
18367            let end_excerpt_id = range.end.excerpt_id;
18368            let range = range.to_point(buffer);
18369            let mut peek_end = range.end;
18370            if range.end.row < buffer.max_row().0 {
18371                peek_end = Point::new(range.end.row + 1, 0);
18372            }
18373            buffer
18374                .diff_hunks_in_range(range.start..peek_end)
18375                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18376        })
18377    }
18378
18379    pub fn has_stageable_diff_hunks_in_ranges(
18380        &self,
18381        ranges: &[Range<Anchor>],
18382        snapshot: &MultiBufferSnapshot,
18383    ) -> bool {
18384        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18385        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18386    }
18387
18388    pub fn toggle_staged_selected_diff_hunks(
18389        &mut self,
18390        _: &::git::ToggleStaged,
18391        _: &mut Window,
18392        cx: &mut Context<Self>,
18393    ) {
18394        let snapshot = self.buffer.read(cx).snapshot(cx);
18395        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18396        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18397        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18398    }
18399
18400    pub fn set_render_diff_hunk_controls(
18401        &mut self,
18402        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18403        cx: &mut Context<Self>,
18404    ) {
18405        self.render_diff_hunk_controls = render_diff_hunk_controls;
18406        cx.notify();
18407    }
18408
18409    pub fn stage_and_next(
18410        &mut self,
18411        _: &::git::StageAndNext,
18412        window: &mut Window,
18413        cx: &mut Context<Self>,
18414    ) {
18415        self.do_stage_or_unstage_and_next(true, window, cx);
18416    }
18417
18418    pub fn unstage_and_next(
18419        &mut self,
18420        _: &::git::UnstageAndNext,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) {
18424        self.do_stage_or_unstage_and_next(false, window, cx);
18425    }
18426
18427    pub fn stage_or_unstage_diff_hunks(
18428        &mut self,
18429        stage: bool,
18430        ranges: Vec<Range<Anchor>>,
18431        cx: &mut Context<Self>,
18432    ) {
18433        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18434        cx.spawn(async move |this, cx| {
18435            task.await?;
18436            this.update(cx, |this, cx| {
18437                let snapshot = this.buffer.read(cx).snapshot(cx);
18438                let chunk_by = this
18439                    .diff_hunks_in_ranges(&ranges, &snapshot)
18440                    .chunk_by(|hunk| hunk.buffer_id);
18441                for (buffer_id, hunks) in &chunk_by {
18442                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18443                }
18444            })
18445        })
18446        .detach_and_log_err(cx);
18447    }
18448
18449    fn save_buffers_for_ranges_if_needed(
18450        &mut self,
18451        ranges: &[Range<Anchor>],
18452        cx: &mut Context<Editor>,
18453    ) -> Task<Result<()>> {
18454        let multibuffer = self.buffer.read(cx);
18455        let snapshot = multibuffer.read(cx);
18456        let buffer_ids: HashSet<_> = ranges
18457            .iter()
18458            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18459            .collect();
18460        drop(snapshot);
18461
18462        let mut buffers = HashSet::default();
18463        for buffer_id in buffer_ids {
18464            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18465                let buffer = buffer_entity.read(cx);
18466                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18467                {
18468                    buffers.insert(buffer_entity);
18469                }
18470            }
18471        }
18472
18473        if let Some(project) = &self.project {
18474            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18475        } else {
18476            Task::ready(Ok(()))
18477        }
18478    }
18479
18480    fn do_stage_or_unstage_and_next(
18481        &mut self,
18482        stage: bool,
18483        window: &mut Window,
18484        cx: &mut Context<Self>,
18485    ) {
18486        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18487
18488        if ranges.iter().any(|range| range.start != range.end) {
18489            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18490            return;
18491        }
18492
18493        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18494        let snapshot = self.snapshot(window, cx);
18495        let position = self.selections.newest::<Point>(cx).head();
18496        let mut row = snapshot
18497            .buffer_snapshot
18498            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18499            .find(|hunk| hunk.row_range.start.0 > position.row)
18500            .map(|hunk| hunk.row_range.start);
18501
18502        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18503        // Outside of the project diff editor, wrap around to the beginning.
18504        if !all_diff_hunks_expanded {
18505            row = row.or_else(|| {
18506                snapshot
18507                    .buffer_snapshot
18508                    .diff_hunks_in_range(Point::zero()..position)
18509                    .find(|hunk| hunk.row_range.end.0 < position.row)
18510                    .map(|hunk| hunk.row_range.start)
18511            });
18512        }
18513
18514        if let Some(row) = row {
18515            let destination = Point::new(row.0, 0);
18516            let autoscroll = Autoscroll::center();
18517
18518            self.unfold_ranges(&[destination..destination], false, false, cx);
18519            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18520                s.select_ranges([destination..destination]);
18521            });
18522        }
18523    }
18524
18525    fn do_stage_or_unstage(
18526        &self,
18527        stage: bool,
18528        buffer_id: BufferId,
18529        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18530        cx: &mut App,
18531    ) -> Option<()> {
18532        let project = self.project()?;
18533        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18534        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18535        let buffer_snapshot = buffer.read(cx).snapshot();
18536        let file_exists = buffer_snapshot
18537            .file()
18538            .is_some_and(|file| file.disk_state().exists());
18539        diff.update(cx, |diff, cx| {
18540            diff.stage_or_unstage_hunks(
18541                stage,
18542                &hunks
18543                    .map(|hunk| buffer_diff::DiffHunk {
18544                        buffer_range: hunk.buffer_range,
18545                        diff_base_byte_range: hunk.diff_base_byte_range,
18546                        secondary_status: hunk.secondary_status,
18547                        range: Point::zero()..Point::zero(), // unused
18548                    })
18549                    .collect::<Vec<_>>(),
18550                &buffer_snapshot,
18551                file_exists,
18552                cx,
18553            )
18554        });
18555        None
18556    }
18557
18558    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18559        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18560        self.buffer
18561            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18562    }
18563
18564    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18565        self.buffer.update(cx, |buffer, cx| {
18566            let ranges = vec![Anchor::min()..Anchor::max()];
18567            if !buffer.all_diff_hunks_expanded()
18568                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18569            {
18570                buffer.collapse_diff_hunks(ranges, cx);
18571                true
18572            } else {
18573                false
18574            }
18575        })
18576    }
18577
18578    fn toggle_diff_hunks_in_ranges(
18579        &mut self,
18580        ranges: Vec<Range<Anchor>>,
18581        cx: &mut Context<Editor>,
18582    ) {
18583        self.buffer.update(cx, |buffer, cx| {
18584            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18585            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18586        })
18587    }
18588
18589    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18590        self.buffer.update(cx, |buffer, cx| {
18591            let snapshot = buffer.snapshot(cx);
18592            let excerpt_id = range.end.excerpt_id;
18593            let point_range = range.to_point(&snapshot);
18594            let expand = !buffer.single_hunk_is_expanded(range, cx);
18595            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18596        })
18597    }
18598
18599    pub(crate) fn apply_all_diff_hunks(
18600        &mut self,
18601        _: &ApplyAllDiffHunks,
18602        window: &mut Window,
18603        cx: &mut Context<Self>,
18604    ) {
18605        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18606
18607        let buffers = self.buffer.read(cx).all_buffers();
18608        for branch_buffer in buffers {
18609            branch_buffer.update(cx, |branch_buffer, cx| {
18610                branch_buffer.merge_into_base(Vec::new(), cx);
18611            });
18612        }
18613
18614        if let Some(project) = self.project.clone() {
18615            self.save(
18616                SaveOptions {
18617                    format: true,
18618                    autosave: false,
18619                },
18620                project,
18621                window,
18622                cx,
18623            )
18624            .detach_and_log_err(cx);
18625        }
18626    }
18627
18628    pub(crate) fn apply_selected_diff_hunks(
18629        &mut self,
18630        _: &ApplyDiffHunk,
18631        window: &mut Window,
18632        cx: &mut Context<Self>,
18633    ) {
18634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18635        let snapshot = self.snapshot(window, cx);
18636        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18637        let mut ranges_by_buffer = HashMap::default();
18638        self.transact(window, cx, |editor, _window, cx| {
18639            for hunk in hunks {
18640                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18641                    ranges_by_buffer
18642                        .entry(buffer.clone())
18643                        .or_insert_with(Vec::new)
18644                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18645                }
18646            }
18647
18648            for (buffer, ranges) in ranges_by_buffer {
18649                buffer.update(cx, |buffer, cx| {
18650                    buffer.merge_into_base(ranges, cx);
18651                });
18652            }
18653        });
18654
18655        if let Some(project) = self.project.clone() {
18656            self.save(
18657                SaveOptions {
18658                    format: true,
18659                    autosave: false,
18660                },
18661                project,
18662                window,
18663                cx,
18664            )
18665            .detach_and_log_err(cx);
18666        }
18667    }
18668
18669    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18670        if hovered != self.gutter_hovered {
18671            self.gutter_hovered = hovered;
18672            cx.notify();
18673        }
18674    }
18675
18676    pub fn insert_blocks(
18677        &mut self,
18678        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18679        autoscroll: Option<Autoscroll>,
18680        cx: &mut Context<Self>,
18681    ) -> Vec<CustomBlockId> {
18682        let blocks = self
18683            .display_map
18684            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18685        if let Some(autoscroll) = autoscroll {
18686            self.request_autoscroll(autoscroll, cx);
18687        }
18688        cx.notify();
18689        blocks
18690    }
18691
18692    pub fn resize_blocks(
18693        &mut self,
18694        heights: HashMap<CustomBlockId, u32>,
18695        autoscroll: Option<Autoscroll>,
18696        cx: &mut Context<Self>,
18697    ) {
18698        self.display_map
18699            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18700        if let Some(autoscroll) = autoscroll {
18701            self.request_autoscroll(autoscroll, cx);
18702        }
18703        cx.notify();
18704    }
18705
18706    pub fn replace_blocks(
18707        &mut self,
18708        renderers: HashMap<CustomBlockId, RenderBlock>,
18709        autoscroll: Option<Autoscroll>,
18710        cx: &mut Context<Self>,
18711    ) {
18712        self.display_map
18713            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18714        if let Some(autoscroll) = autoscroll {
18715            self.request_autoscroll(autoscroll, cx);
18716        }
18717        cx.notify();
18718    }
18719
18720    pub fn remove_blocks(
18721        &mut self,
18722        block_ids: HashSet<CustomBlockId>,
18723        autoscroll: Option<Autoscroll>,
18724        cx: &mut Context<Self>,
18725    ) {
18726        self.display_map.update(cx, |display_map, cx| {
18727            display_map.remove_blocks(block_ids, cx)
18728        });
18729        if let Some(autoscroll) = autoscroll {
18730            self.request_autoscroll(autoscroll, cx);
18731        }
18732        cx.notify();
18733    }
18734
18735    pub fn row_for_block(
18736        &self,
18737        block_id: CustomBlockId,
18738        cx: &mut Context<Self>,
18739    ) -> Option<DisplayRow> {
18740        self.display_map
18741            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18742    }
18743
18744    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18745        self.focused_block = Some(focused_block);
18746    }
18747
18748    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18749        self.focused_block.take()
18750    }
18751
18752    pub fn insert_creases(
18753        &mut self,
18754        creases: impl IntoIterator<Item = Crease<Anchor>>,
18755        cx: &mut Context<Self>,
18756    ) -> Vec<CreaseId> {
18757        self.display_map
18758            .update(cx, |map, cx| map.insert_creases(creases, cx))
18759    }
18760
18761    pub fn remove_creases(
18762        &mut self,
18763        ids: impl IntoIterator<Item = CreaseId>,
18764        cx: &mut Context<Self>,
18765    ) -> Vec<(CreaseId, Range<Anchor>)> {
18766        self.display_map
18767            .update(cx, |map, cx| map.remove_creases(ids, cx))
18768    }
18769
18770    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18771        self.display_map
18772            .update(cx, |map, cx| map.snapshot(cx))
18773            .longest_row()
18774    }
18775
18776    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18777        self.display_map
18778            .update(cx, |map, cx| map.snapshot(cx))
18779            .max_point()
18780    }
18781
18782    pub fn text(&self, cx: &App) -> String {
18783        self.buffer.read(cx).read(cx).text()
18784    }
18785
18786    pub fn is_empty(&self, cx: &App) -> bool {
18787        self.buffer.read(cx).read(cx).is_empty()
18788    }
18789
18790    pub fn text_option(&self, cx: &App) -> Option<String> {
18791        let text = self.text(cx);
18792        let text = text.trim();
18793
18794        if text.is_empty() {
18795            return None;
18796        }
18797
18798        Some(text.to_string())
18799    }
18800
18801    pub fn set_text(
18802        &mut self,
18803        text: impl Into<Arc<str>>,
18804        window: &mut Window,
18805        cx: &mut Context<Self>,
18806    ) {
18807        self.transact(window, cx, |this, _, cx| {
18808            this.buffer
18809                .read(cx)
18810                .as_singleton()
18811                .expect("you can only call set_text on editors for singleton buffers")
18812                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18813        });
18814    }
18815
18816    pub fn display_text(&self, cx: &mut App) -> String {
18817        self.display_map
18818            .update(cx, |map, cx| map.snapshot(cx))
18819            .text()
18820    }
18821
18822    fn create_minimap(
18823        &self,
18824        minimap_settings: MinimapSettings,
18825        window: &mut Window,
18826        cx: &mut Context<Self>,
18827    ) -> Option<Entity<Self>> {
18828        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18829            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18830    }
18831
18832    fn initialize_new_minimap(
18833        &self,
18834        minimap_settings: MinimapSettings,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) -> Entity<Self> {
18838        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18839
18840        let mut minimap = Editor::new_internal(
18841            EditorMode::Minimap {
18842                parent: cx.weak_entity(),
18843            },
18844            self.buffer.clone(),
18845            None,
18846            Some(self.display_map.clone()),
18847            window,
18848            cx,
18849        );
18850        minimap.scroll_manager.clone_state(&self.scroll_manager);
18851        minimap.set_text_style_refinement(TextStyleRefinement {
18852            font_size: Some(MINIMAP_FONT_SIZE),
18853            font_weight: Some(MINIMAP_FONT_WEIGHT),
18854            ..Default::default()
18855        });
18856        minimap.update_minimap_configuration(minimap_settings, cx);
18857        cx.new(|_| minimap)
18858    }
18859
18860    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18861        let current_line_highlight = minimap_settings
18862            .current_line_highlight
18863            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18864        self.set_current_line_highlight(Some(current_line_highlight));
18865    }
18866
18867    pub fn minimap(&self) -> Option<&Entity<Self>> {
18868        self.minimap
18869            .as_ref()
18870            .filter(|_| self.minimap_visibility.visible())
18871    }
18872
18873    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18874        let mut wrap_guides = smallvec![];
18875
18876        if self.show_wrap_guides == Some(false) {
18877            return wrap_guides;
18878        }
18879
18880        let settings = self.buffer.read(cx).language_settings(cx);
18881        if settings.show_wrap_guides {
18882            match self.soft_wrap_mode(cx) {
18883                SoftWrap::Column(soft_wrap) => {
18884                    wrap_guides.push((soft_wrap as usize, true));
18885                }
18886                SoftWrap::Bounded(soft_wrap) => {
18887                    wrap_guides.push((soft_wrap as usize, true));
18888                }
18889                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18890            }
18891            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18892        }
18893
18894        wrap_guides
18895    }
18896
18897    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18898        let settings = self.buffer.read(cx).language_settings(cx);
18899        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18900        match mode {
18901            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18902                SoftWrap::None
18903            }
18904            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18905            language_settings::SoftWrap::PreferredLineLength => {
18906                SoftWrap::Column(settings.preferred_line_length)
18907            }
18908            language_settings::SoftWrap::Bounded => {
18909                SoftWrap::Bounded(settings.preferred_line_length)
18910            }
18911        }
18912    }
18913
18914    pub fn set_soft_wrap_mode(
18915        &mut self,
18916        mode: language_settings::SoftWrap,
18917
18918        cx: &mut Context<Self>,
18919    ) {
18920        self.soft_wrap_mode_override = Some(mode);
18921        cx.notify();
18922    }
18923
18924    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18925        self.hard_wrap = hard_wrap;
18926        cx.notify();
18927    }
18928
18929    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18930        self.text_style_refinement = Some(style);
18931    }
18932
18933    /// called by the Element so we know what style we were most recently rendered with.
18934    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18935        // We intentionally do not inform the display map about the minimap style
18936        // so that wrapping is not recalculated and stays consistent for the editor
18937        // and its linked minimap.
18938        if !self.mode.is_minimap() {
18939            let font = style.text.font();
18940            let font_size = style.text.font_size.to_pixels(window.rem_size());
18941            let display_map = self
18942                .placeholder_display_map
18943                .as_ref()
18944                .filter(|_| self.is_empty(cx))
18945                .unwrap_or(&self.display_map);
18946
18947            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18948        }
18949        self.style = Some(style);
18950    }
18951
18952    pub fn style(&self) -> Option<&EditorStyle> {
18953        self.style.as_ref()
18954    }
18955
18956    // Called by the element. This method is not designed to be called outside of the editor
18957    // element's layout code because it does not notify when rewrapping is computed synchronously.
18958    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18959        if self.is_empty(cx) {
18960            self.placeholder_display_map
18961                .as_ref()
18962                .map_or(false, |display_map| {
18963                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18964                })
18965        } else {
18966            self.display_map
18967                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18968        }
18969    }
18970
18971    pub fn set_soft_wrap(&mut self) {
18972        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18973    }
18974
18975    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18976        if self.soft_wrap_mode_override.is_some() {
18977            self.soft_wrap_mode_override.take();
18978        } else {
18979            let soft_wrap = match self.soft_wrap_mode(cx) {
18980                SoftWrap::GitDiff => return,
18981                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18982                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18983                    language_settings::SoftWrap::None
18984                }
18985            };
18986            self.soft_wrap_mode_override = Some(soft_wrap);
18987        }
18988        cx.notify();
18989    }
18990
18991    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18992        let Some(workspace) = self.workspace() else {
18993            return;
18994        };
18995        let fs = workspace.read(cx).app_state().fs.clone();
18996        let current_show = TabBarSettings::get_global(cx).show;
18997        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18998            setting.show = Some(!current_show);
18999        });
19000    }
19001
19002    pub fn toggle_indent_guides(
19003        &mut self,
19004        _: &ToggleIndentGuides,
19005        _: &mut Window,
19006        cx: &mut Context<Self>,
19007    ) {
19008        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19009            self.buffer
19010                .read(cx)
19011                .language_settings(cx)
19012                .indent_guides
19013                .enabled
19014        });
19015        self.show_indent_guides = Some(!currently_enabled);
19016        cx.notify();
19017    }
19018
19019    fn should_show_indent_guides(&self) -> Option<bool> {
19020        self.show_indent_guides
19021    }
19022
19023    pub fn toggle_line_numbers(
19024        &mut self,
19025        _: &ToggleLineNumbers,
19026        _: &mut Window,
19027        cx: &mut Context<Self>,
19028    ) {
19029        let mut editor_settings = EditorSettings::get_global(cx).clone();
19030        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19031        EditorSettings::override_global(editor_settings, cx);
19032    }
19033
19034    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19035        if let Some(show_line_numbers) = self.show_line_numbers {
19036            return show_line_numbers;
19037        }
19038        EditorSettings::get_global(cx).gutter.line_numbers
19039    }
19040
19041    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19042        self.use_relative_line_numbers
19043            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19044    }
19045
19046    pub fn toggle_relative_line_numbers(
19047        &mut self,
19048        _: &ToggleRelativeLineNumbers,
19049        _: &mut Window,
19050        cx: &mut Context<Self>,
19051    ) {
19052        let is_relative = self.should_use_relative_line_numbers(cx);
19053        self.set_relative_line_number(Some(!is_relative), cx)
19054    }
19055
19056    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19057        self.use_relative_line_numbers = is_relative;
19058        cx.notify();
19059    }
19060
19061    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19062        self.show_gutter = show_gutter;
19063        cx.notify();
19064    }
19065
19066    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19067        self.show_scrollbars = ScrollbarAxes {
19068            horizontal: show,
19069            vertical: show,
19070        };
19071        cx.notify();
19072    }
19073
19074    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19075        self.show_scrollbars.vertical = show;
19076        cx.notify();
19077    }
19078
19079    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19080        self.show_scrollbars.horizontal = show;
19081        cx.notify();
19082    }
19083
19084    pub fn set_minimap_visibility(
19085        &mut self,
19086        minimap_visibility: MinimapVisibility,
19087        window: &mut Window,
19088        cx: &mut Context<Self>,
19089    ) {
19090        if self.minimap_visibility != minimap_visibility {
19091            if minimap_visibility.visible() && self.minimap.is_none() {
19092                let minimap_settings = EditorSettings::get_global(cx).minimap;
19093                self.minimap =
19094                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19095            }
19096            self.minimap_visibility = minimap_visibility;
19097            cx.notify();
19098        }
19099    }
19100
19101    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19102        self.set_show_scrollbars(false, cx);
19103        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19104    }
19105
19106    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19107        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19108    }
19109
19110    /// Normally the text in full mode and auto height editors is padded on the
19111    /// left side by roughly half a character width for improved hit testing.
19112    ///
19113    /// Use this method to disable this for cases where this is not wanted (e.g.
19114    /// if you want to align the editor text with some other text above or below)
19115    /// or if you want to add this padding to single-line editors.
19116    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19117        self.offset_content = offset_content;
19118        cx.notify();
19119    }
19120
19121    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19122        self.show_line_numbers = Some(show_line_numbers);
19123        cx.notify();
19124    }
19125
19126    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19127        self.disable_expand_excerpt_buttons = true;
19128        cx.notify();
19129    }
19130
19131    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19132        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19133        cx.notify();
19134    }
19135
19136    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19137        self.show_code_actions = Some(show_code_actions);
19138        cx.notify();
19139    }
19140
19141    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19142        self.show_runnables = Some(show_runnables);
19143        cx.notify();
19144    }
19145
19146    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19147        self.show_breakpoints = Some(show_breakpoints);
19148        cx.notify();
19149    }
19150
19151    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19152        if self.display_map.read(cx).masked != masked {
19153            self.display_map.update(cx, |map, _| map.masked = masked);
19154        }
19155        cx.notify()
19156    }
19157
19158    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19159        self.show_wrap_guides = Some(show_wrap_guides);
19160        cx.notify();
19161    }
19162
19163    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19164        self.show_indent_guides = Some(show_indent_guides);
19165        cx.notify();
19166    }
19167
19168    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19169        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19170            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19171                && let Some(dir) = file.abs_path(cx).parent()
19172            {
19173                return Some(dir.to_owned());
19174            }
19175
19176            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19177                return Some(project_path.path.to_path_buf());
19178            }
19179        }
19180
19181        None
19182    }
19183
19184    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19185        self.active_excerpt(cx)?
19186            .1
19187            .read(cx)
19188            .file()
19189            .and_then(|f| f.as_local())
19190    }
19191
19192    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19193        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19194            let buffer = buffer.read(cx);
19195            if let Some(project_path) = buffer.project_path(cx) {
19196                let project = self.project()?.read(cx);
19197                project.absolute_path(&project_path, cx)
19198            } else {
19199                buffer
19200                    .file()
19201                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19202            }
19203        })
19204    }
19205
19206    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19207        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19208            let project_path = buffer.read(cx).project_path(cx)?;
19209            let project = self.project()?.read(cx);
19210            let entry = project.entry_for_path(&project_path, cx)?;
19211            let path = entry.path.to_path_buf();
19212            Some(path)
19213        })
19214    }
19215
19216    pub fn reveal_in_finder(
19217        &mut self,
19218        _: &RevealInFileManager,
19219        _window: &mut Window,
19220        cx: &mut Context<Self>,
19221    ) {
19222        if let Some(target) = self.target_file(cx) {
19223            cx.reveal_path(&target.abs_path(cx));
19224        }
19225    }
19226
19227    pub fn copy_path(
19228        &mut self,
19229        _: &zed_actions::workspace::CopyPath,
19230        _window: &mut Window,
19231        cx: &mut Context<Self>,
19232    ) {
19233        if let Some(path) = self.target_file_abs_path(cx)
19234            && let Some(path) = path.to_str()
19235        {
19236            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19237        }
19238    }
19239
19240    pub fn copy_relative_path(
19241        &mut self,
19242        _: &zed_actions::workspace::CopyRelativePath,
19243        _window: &mut Window,
19244        cx: &mut Context<Self>,
19245    ) {
19246        if let Some(path) = self.target_file_path(cx)
19247            && let Some(path) = path.to_str()
19248        {
19249            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19250        }
19251    }
19252
19253    /// Returns the project path for the editor's buffer, if any buffer is
19254    /// opened in the editor.
19255    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19256        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19257            buffer.read(cx).project_path(cx)
19258        } else {
19259            None
19260        }
19261    }
19262
19263    // Returns true if the editor handled a go-to-line request
19264    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19265        maybe!({
19266            let breakpoint_store = self.breakpoint_store.as_ref()?;
19267
19268            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19269            else {
19270                self.clear_row_highlights::<ActiveDebugLine>();
19271                return None;
19272            };
19273
19274            let position = active_stack_frame.position;
19275            let buffer_id = position.buffer_id?;
19276            let snapshot = self
19277                .project
19278                .as_ref()?
19279                .read(cx)
19280                .buffer_for_id(buffer_id, cx)?
19281                .read(cx)
19282                .snapshot();
19283
19284            let mut handled = false;
19285            for (id, ExcerptRange { context, .. }) in
19286                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19287            {
19288                if context.start.cmp(&position, &snapshot).is_ge()
19289                    || context.end.cmp(&position, &snapshot).is_lt()
19290                {
19291                    continue;
19292                }
19293                let snapshot = self.buffer.read(cx).snapshot(cx);
19294                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19295
19296                handled = true;
19297                self.clear_row_highlights::<ActiveDebugLine>();
19298
19299                self.go_to_line::<ActiveDebugLine>(
19300                    multibuffer_anchor,
19301                    Some(cx.theme().colors().editor_debugger_active_line_background),
19302                    window,
19303                    cx,
19304                );
19305
19306                cx.notify();
19307            }
19308
19309            handled.then_some(())
19310        })
19311        .is_some()
19312    }
19313
19314    pub fn copy_file_name_without_extension(
19315        &mut self,
19316        _: &CopyFileNameWithoutExtension,
19317        _: &mut Window,
19318        cx: &mut Context<Self>,
19319    ) {
19320        if let Some(file) = self.target_file(cx)
19321            && let Some(file_stem) = file.path().file_stem()
19322            && let Some(name) = file_stem.to_str()
19323        {
19324            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19325        }
19326    }
19327
19328    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19329        if let Some(file) = self.target_file(cx)
19330            && let Some(file_name) = file.path().file_name()
19331            && let Some(name) = file_name.to_str()
19332        {
19333            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19334        }
19335    }
19336
19337    pub fn toggle_git_blame(
19338        &mut self,
19339        _: &::git::Blame,
19340        window: &mut Window,
19341        cx: &mut Context<Self>,
19342    ) {
19343        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19344
19345        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19346            self.start_git_blame(true, window, cx);
19347        }
19348
19349        cx.notify();
19350    }
19351
19352    pub fn toggle_git_blame_inline(
19353        &mut self,
19354        _: &ToggleGitBlameInline,
19355        window: &mut Window,
19356        cx: &mut Context<Self>,
19357    ) {
19358        self.toggle_git_blame_inline_internal(true, window, cx);
19359        cx.notify();
19360    }
19361
19362    pub fn open_git_blame_commit(
19363        &mut self,
19364        _: &OpenGitBlameCommit,
19365        window: &mut Window,
19366        cx: &mut Context<Self>,
19367    ) {
19368        self.open_git_blame_commit_internal(window, cx);
19369    }
19370
19371    fn open_git_blame_commit_internal(
19372        &mut self,
19373        window: &mut Window,
19374        cx: &mut Context<Self>,
19375    ) -> Option<()> {
19376        let blame = self.blame.as_ref()?;
19377        let snapshot = self.snapshot(window, cx);
19378        let cursor = self.selections.newest::<Point>(cx).head();
19379        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19380        let (_, blame_entry) = blame
19381            .update(cx, |blame, cx| {
19382                blame
19383                    .blame_for_rows(
19384                        &[RowInfo {
19385                            buffer_id: Some(buffer.remote_id()),
19386                            buffer_row: Some(point.row),
19387                            ..Default::default()
19388                        }],
19389                        cx,
19390                    )
19391                    .next()
19392            })
19393            .flatten()?;
19394        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19395        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19396        let workspace = self.workspace()?.downgrade();
19397        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19398        None
19399    }
19400
19401    pub fn git_blame_inline_enabled(&self) -> bool {
19402        self.git_blame_inline_enabled
19403    }
19404
19405    pub fn toggle_selection_menu(
19406        &mut self,
19407        _: &ToggleSelectionMenu,
19408        _: &mut Window,
19409        cx: &mut Context<Self>,
19410    ) {
19411        self.show_selection_menu = self
19412            .show_selection_menu
19413            .map(|show_selections_menu| !show_selections_menu)
19414            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19415
19416        cx.notify();
19417    }
19418
19419    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19420        self.show_selection_menu
19421            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19422    }
19423
19424    fn start_git_blame(
19425        &mut self,
19426        user_triggered: bool,
19427        window: &mut Window,
19428        cx: &mut Context<Self>,
19429    ) {
19430        if let Some(project) = self.project() {
19431            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19432                && buffer.read(cx).file().is_none()
19433            {
19434                return;
19435            }
19436
19437            let focused = self.focus_handle(cx).contains_focused(window, cx);
19438
19439            let project = project.clone();
19440            let blame = cx
19441                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19442            self.blame_subscription =
19443                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19444            self.blame = Some(blame);
19445        }
19446    }
19447
19448    fn toggle_git_blame_inline_internal(
19449        &mut self,
19450        user_triggered: bool,
19451        window: &mut Window,
19452        cx: &mut Context<Self>,
19453    ) {
19454        if self.git_blame_inline_enabled {
19455            self.git_blame_inline_enabled = false;
19456            self.show_git_blame_inline = false;
19457            self.show_git_blame_inline_delay_task.take();
19458        } else {
19459            self.git_blame_inline_enabled = true;
19460            self.start_git_blame_inline(user_triggered, window, cx);
19461        }
19462
19463        cx.notify();
19464    }
19465
19466    fn start_git_blame_inline(
19467        &mut self,
19468        user_triggered: bool,
19469        window: &mut Window,
19470        cx: &mut Context<Self>,
19471    ) {
19472        self.start_git_blame(user_triggered, window, cx);
19473
19474        if ProjectSettings::get_global(cx)
19475            .git
19476            .inline_blame_delay()
19477            .is_some()
19478        {
19479            self.start_inline_blame_timer(window, cx);
19480        } else {
19481            self.show_git_blame_inline = true
19482        }
19483    }
19484
19485    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19486        self.blame.as_ref()
19487    }
19488
19489    pub fn show_git_blame_gutter(&self) -> bool {
19490        self.show_git_blame_gutter
19491    }
19492
19493    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19494        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19495    }
19496
19497    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19498        self.show_git_blame_inline
19499            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19500            && !self.newest_selection_head_on_empty_line(cx)
19501            && self.has_blame_entries(cx)
19502    }
19503
19504    fn has_blame_entries(&self, cx: &App) -> bool {
19505        self.blame()
19506            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19507    }
19508
19509    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19510        let cursor_anchor = self.selections.newest_anchor().head();
19511
19512        let snapshot = self.buffer.read(cx).snapshot(cx);
19513        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19514
19515        snapshot.line_len(buffer_row) == 0
19516    }
19517
19518    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19519        let buffer_and_selection = maybe!({
19520            let selection = self.selections.newest::<Point>(cx);
19521            let selection_range = selection.range();
19522
19523            let multi_buffer = self.buffer().read(cx);
19524            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19525            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19526
19527            let (buffer, range, _) = if selection.reversed {
19528                buffer_ranges.first()
19529            } else {
19530                buffer_ranges.last()
19531            }?;
19532
19533            let selection = text::ToPoint::to_point(&range.start, buffer).row
19534                ..text::ToPoint::to_point(&range.end, buffer).row;
19535            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19536        });
19537
19538        let Some((buffer, selection)) = buffer_and_selection else {
19539            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19540        };
19541
19542        let Some(project) = self.project() else {
19543            return Task::ready(Err(anyhow!("editor does not have project")));
19544        };
19545
19546        project.update(cx, |project, cx| {
19547            project.get_permalink_to_line(&buffer, selection, cx)
19548        })
19549    }
19550
19551    pub fn copy_permalink_to_line(
19552        &mut self,
19553        _: &CopyPermalinkToLine,
19554        window: &mut Window,
19555        cx: &mut Context<Self>,
19556    ) {
19557        let permalink_task = self.get_permalink_to_line(cx);
19558        let workspace = self.workspace();
19559
19560        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19561            Ok(permalink) => {
19562                cx.update(|_, cx| {
19563                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19564                })
19565                .ok();
19566            }
19567            Err(err) => {
19568                let message = format!("Failed to copy permalink: {err}");
19569
19570                anyhow::Result::<()>::Err(err).log_err();
19571
19572                if let Some(workspace) = workspace {
19573                    workspace
19574                        .update_in(cx, |workspace, _, cx| {
19575                            struct CopyPermalinkToLine;
19576
19577                            workspace.show_toast(
19578                                Toast::new(
19579                                    NotificationId::unique::<CopyPermalinkToLine>(),
19580                                    message,
19581                                ),
19582                                cx,
19583                            )
19584                        })
19585                        .ok();
19586                }
19587            }
19588        })
19589        .detach();
19590    }
19591
19592    pub fn copy_file_location(
19593        &mut self,
19594        _: &CopyFileLocation,
19595        _: &mut Window,
19596        cx: &mut Context<Self>,
19597    ) {
19598        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19599        if let Some(file) = self.target_file(cx)
19600            && let Some(path) = file.path().to_str()
19601        {
19602            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19603        }
19604    }
19605
19606    pub fn open_permalink_to_line(
19607        &mut self,
19608        _: &OpenPermalinkToLine,
19609        window: &mut Window,
19610        cx: &mut Context<Self>,
19611    ) {
19612        let permalink_task = self.get_permalink_to_line(cx);
19613        let workspace = self.workspace();
19614
19615        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19616            Ok(permalink) => {
19617                cx.update(|_, cx| {
19618                    cx.open_url(permalink.as_ref());
19619                })
19620                .ok();
19621            }
19622            Err(err) => {
19623                let message = format!("Failed to open permalink: {err}");
19624
19625                anyhow::Result::<()>::Err(err).log_err();
19626
19627                if let Some(workspace) = workspace {
19628                    workspace
19629                        .update(cx, |workspace, cx| {
19630                            struct OpenPermalinkToLine;
19631
19632                            workspace.show_toast(
19633                                Toast::new(
19634                                    NotificationId::unique::<OpenPermalinkToLine>(),
19635                                    message,
19636                                ),
19637                                cx,
19638                            )
19639                        })
19640                        .ok();
19641                }
19642            }
19643        })
19644        .detach();
19645    }
19646
19647    pub fn insert_uuid_v4(
19648        &mut self,
19649        _: &InsertUuidV4,
19650        window: &mut Window,
19651        cx: &mut Context<Self>,
19652    ) {
19653        self.insert_uuid(UuidVersion::V4, window, cx);
19654    }
19655
19656    pub fn insert_uuid_v7(
19657        &mut self,
19658        _: &InsertUuidV7,
19659        window: &mut Window,
19660        cx: &mut Context<Self>,
19661    ) {
19662        self.insert_uuid(UuidVersion::V7, window, cx);
19663    }
19664
19665    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19667        self.transact(window, cx, |this, window, cx| {
19668            let edits = this
19669                .selections
19670                .all::<Point>(cx)
19671                .into_iter()
19672                .map(|selection| {
19673                    let uuid = match version {
19674                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19675                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19676                    };
19677
19678                    (selection.range(), uuid.to_string())
19679                });
19680            this.edit(edits, cx);
19681            this.refresh_edit_prediction(true, false, window, cx);
19682        });
19683    }
19684
19685    pub fn open_selections_in_multibuffer(
19686        &mut self,
19687        _: &OpenSelectionsInMultibuffer,
19688        window: &mut Window,
19689        cx: &mut Context<Self>,
19690    ) {
19691        let multibuffer = self.buffer.read(cx);
19692
19693        let Some(buffer) = multibuffer.as_singleton() else {
19694            return;
19695        };
19696
19697        let Some(workspace) = self.workspace() else {
19698            return;
19699        };
19700
19701        let title = multibuffer.title(cx).to_string();
19702
19703        let locations = self
19704            .selections
19705            .all_anchors(cx)
19706            .iter()
19707            .map(|selection| Location {
19708                buffer: buffer.clone(),
19709                range: selection.start.text_anchor..selection.end.text_anchor,
19710            })
19711            .collect::<Vec<_>>();
19712
19713        cx.spawn_in(window, async move |_, cx| {
19714            workspace.update_in(cx, |workspace, window, cx| {
19715                Self::open_locations_in_multibuffer(
19716                    workspace,
19717                    locations,
19718                    format!("Selections for '{title}'"),
19719                    false,
19720                    MultibufferSelectionMode::All,
19721                    window,
19722                    cx,
19723                );
19724            })
19725        })
19726        .detach();
19727    }
19728
19729    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19730    /// last highlight added will be used.
19731    ///
19732    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19733    pub fn highlight_rows<T: 'static>(
19734        &mut self,
19735        range: Range<Anchor>,
19736        color: Hsla,
19737        options: RowHighlightOptions,
19738        cx: &mut Context<Self>,
19739    ) {
19740        let snapshot = self.buffer().read(cx).snapshot(cx);
19741        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19742        let ix = row_highlights.binary_search_by(|highlight| {
19743            Ordering::Equal
19744                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19745                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19746        });
19747
19748        if let Err(mut ix) = ix {
19749            let index = post_inc(&mut self.highlight_order);
19750
19751            // If this range intersects with the preceding highlight, then merge it with
19752            // the preceding highlight. Otherwise insert a new highlight.
19753            let mut merged = false;
19754            if ix > 0 {
19755                let prev_highlight = &mut row_highlights[ix - 1];
19756                if prev_highlight
19757                    .range
19758                    .end
19759                    .cmp(&range.start, &snapshot)
19760                    .is_ge()
19761                {
19762                    ix -= 1;
19763                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19764                        prev_highlight.range.end = range.end;
19765                    }
19766                    merged = true;
19767                    prev_highlight.index = index;
19768                    prev_highlight.color = color;
19769                    prev_highlight.options = options;
19770                }
19771            }
19772
19773            if !merged {
19774                row_highlights.insert(
19775                    ix,
19776                    RowHighlight {
19777                        range,
19778                        index,
19779                        color,
19780                        options,
19781                        type_id: TypeId::of::<T>(),
19782                    },
19783                );
19784            }
19785
19786            // If any of the following highlights intersect with this one, merge them.
19787            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19788                let highlight = &row_highlights[ix];
19789                if next_highlight
19790                    .range
19791                    .start
19792                    .cmp(&highlight.range.end, &snapshot)
19793                    .is_le()
19794                {
19795                    if next_highlight
19796                        .range
19797                        .end
19798                        .cmp(&highlight.range.end, &snapshot)
19799                        .is_gt()
19800                    {
19801                        row_highlights[ix].range.end = next_highlight.range.end;
19802                    }
19803                    row_highlights.remove(ix + 1);
19804                } else {
19805                    break;
19806                }
19807            }
19808        }
19809    }
19810
19811    /// Remove any highlighted row ranges of the given type that intersect the
19812    /// given ranges.
19813    pub fn remove_highlighted_rows<T: 'static>(
19814        &mut self,
19815        ranges_to_remove: Vec<Range<Anchor>>,
19816        cx: &mut Context<Self>,
19817    ) {
19818        let snapshot = self.buffer().read(cx).snapshot(cx);
19819        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19820        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19821        row_highlights.retain(|highlight| {
19822            while let Some(range_to_remove) = ranges_to_remove.peek() {
19823                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19824                    Ordering::Less | Ordering::Equal => {
19825                        ranges_to_remove.next();
19826                    }
19827                    Ordering::Greater => {
19828                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19829                            Ordering::Less | Ordering::Equal => {
19830                                return false;
19831                            }
19832                            Ordering::Greater => break,
19833                        }
19834                    }
19835                }
19836            }
19837
19838            true
19839        })
19840    }
19841
19842    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19843    pub fn clear_row_highlights<T: 'static>(&mut self) {
19844        self.highlighted_rows.remove(&TypeId::of::<T>());
19845    }
19846
19847    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19848    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19849        self.highlighted_rows
19850            .get(&TypeId::of::<T>())
19851            .map_or(&[] as &[_], |vec| vec.as_slice())
19852            .iter()
19853            .map(|highlight| (highlight.range.clone(), highlight.color))
19854    }
19855
19856    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19857    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19858    /// Allows to ignore certain kinds of highlights.
19859    pub fn highlighted_display_rows(
19860        &self,
19861        window: &mut Window,
19862        cx: &mut App,
19863    ) -> BTreeMap<DisplayRow, LineHighlight> {
19864        let snapshot = self.snapshot(window, cx);
19865        let mut used_highlight_orders = HashMap::default();
19866        self.highlighted_rows
19867            .iter()
19868            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19869            .fold(
19870                BTreeMap::<DisplayRow, LineHighlight>::new(),
19871                |mut unique_rows, highlight| {
19872                    let start = highlight.range.start.to_display_point(&snapshot);
19873                    let end = highlight.range.end.to_display_point(&snapshot);
19874                    let start_row = start.row().0;
19875                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19876                        && end.column() == 0
19877                    {
19878                        end.row().0.saturating_sub(1)
19879                    } else {
19880                        end.row().0
19881                    };
19882                    for row in start_row..=end_row {
19883                        let used_index =
19884                            used_highlight_orders.entry(row).or_insert(highlight.index);
19885                        if highlight.index >= *used_index {
19886                            *used_index = highlight.index;
19887                            unique_rows.insert(
19888                                DisplayRow(row),
19889                                LineHighlight {
19890                                    include_gutter: highlight.options.include_gutter,
19891                                    border: None,
19892                                    background: highlight.color.into(),
19893                                    type_id: Some(highlight.type_id),
19894                                },
19895                            );
19896                        }
19897                    }
19898                    unique_rows
19899                },
19900            )
19901    }
19902
19903    pub fn highlighted_display_row_for_autoscroll(
19904        &self,
19905        snapshot: &DisplaySnapshot,
19906    ) -> Option<DisplayRow> {
19907        self.highlighted_rows
19908            .values()
19909            .flat_map(|highlighted_rows| highlighted_rows.iter())
19910            .filter_map(|highlight| {
19911                if highlight.options.autoscroll {
19912                    Some(highlight.range.start.to_display_point(snapshot).row())
19913                } else {
19914                    None
19915                }
19916            })
19917            .min()
19918    }
19919
19920    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19921        self.highlight_background::<SearchWithinRange>(
19922            ranges,
19923            |colors| colors.colors().editor_document_highlight_read_background,
19924            cx,
19925        )
19926    }
19927
19928    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19929        self.breadcrumb_header = Some(new_header);
19930    }
19931
19932    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19933        self.clear_background_highlights::<SearchWithinRange>(cx);
19934    }
19935
19936    pub fn highlight_background<T: 'static>(
19937        &mut self,
19938        ranges: &[Range<Anchor>],
19939        color_fetcher: fn(&Theme) -> Hsla,
19940        cx: &mut Context<Self>,
19941    ) {
19942        self.background_highlights.insert(
19943            HighlightKey::Type(TypeId::of::<T>()),
19944            (color_fetcher, Arc::from(ranges)),
19945        );
19946        self.scrollbar_marker_state.dirty = true;
19947        cx.notify();
19948    }
19949
19950    pub fn highlight_background_key<T: 'static>(
19951        &mut self,
19952        key: usize,
19953        ranges: &[Range<Anchor>],
19954        color_fetcher: fn(&Theme) -> Hsla,
19955        cx: &mut Context<Self>,
19956    ) {
19957        self.background_highlights.insert(
19958            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19959            (color_fetcher, Arc::from(ranges)),
19960        );
19961        self.scrollbar_marker_state.dirty = true;
19962        cx.notify();
19963    }
19964
19965    pub fn clear_background_highlights<T: 'static>(
19966        &mut self,
19967        cx: &mut Context<Self>,
19968    ) -> Option<BackgroundHighlight> {
19969        let text_highlights = self
19970            .background_highlights
19971            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19972        if !text_highlights.1.is_empty() {
19973            self.scrollbar_marker_state.dirty = true;
19974            cx.notify();
19975        }
19976        Some(text_highlights)
19977    }
19978
19979    pub fn highlight_gutter<T: 'static>(
19980        &mut self,
19981        ranges: impl Into<Vec<Range<Anchor>>>,
19982        color_fetcher: fn(&App) -> Hsla,
19983        cx: &mut Context<Self>,
19984    ) {
19985        self.gutter_highlights
19986            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19987        cx.notify();
19988    }
19989
19990    pub fn clear_gutter_highlights<T: 'static>(
19991        &mut self,
19992        cx: &mut Context<Self>,
19993    ) -> Option<GutterHighlight> {
19994        cx.notify();
19995        self.gutter_highlights.remove(&TypeId::of::<T>())
19996    }
19997
19998    pub fn insert_gutter_highlight<T: 'static>(
19999        &mut self,
20000        range: Range<Anchor>,
20001        color_fetcher: fn(&App) -> Hsla,
20002        cx: &mut Context<Self>,
20003    ) {
20004        let snapshot = self.buffer().read(cx).snapshot(cx);
20005        let mut highlights = self
20006            .gutter_highlights
20007            .remove(&TypeId::of::<T>())
20008            .map(|(_, highlights)| highlights)
20009            .unwrap_or_default();
20010        let ix = highlights.binary_search_by(|highlight| {
20011            Ordering::Equal
20012                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20013                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20014        });
20015        if let Err(ix) = ix {
20016            highlights.insert(ix, range);
20017        }
20018        self.gutter_highlights
20019            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20020    }
20021
20022    pub fn remove_gutter_highlights<T: 'static>(
20023        &mut self,
20024        ranges_to_remove: Vec<Range<Anchor>>,
20025        cx: &mut Context<Self>,
20026    ) {
20027        let snapshot = self.buffer().read(cx).snapshot(cx);
20028        let Some((color_fetcher, mut gutter_highlights)) =
20029            self.gutter_highlights.remove(&TypeId::of::<T>())
20030        else {
20031            return;
20032        };
20033        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20034        gutter_highlights.retain(|highlight| {
20035            while let Some(range_to_remove) = ranges_to_remove.peek() {
20036                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20037                    Ordering::Less | Ordering::Equal => {
20038                        ranges_to_remove.next();
20039                    }
20040                    Ordering::Greater => {
20041                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20042                            Ordering::Less | Ordering::Equal => {
20043                                return false;
20044                            }
20045                            Ordering::Greater => break,
20046                        }
20047                    }
20048                }
20049            }
20050
20051            true
20052        });
20053        self.gutter_highlights
20054            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20055    }
20056
20057    #[cfg(feature = "test-support")]
20058    pub fn all_text_highlights(
20059        &self,
20060        window: &mut Window,
20061        cx: &mut Context<Self>,
20062    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20063        let snapshot = self.snapshot(window, cx);
20064        self.display_map.update(cx, |display_map, _| {
20065            display_map
20066                .all_text_highlights()
20067                .map(|highlight| {
20068                    let (style, ranges) = highlight.as_ref();
20069                    (
20070                        *style,
20071                        ranges
20072                            .iter()
20073                            .map(|range| range.clone().to_display_points(&snapshot))
20074                            .collect(),
20075                    )
20076                })
20077                .collect()
20078        })
20079    }
20080
20081    #[cfg(feature = "test-support")]
20082    pub fn all_text_background_highlights(
20083        &self,
20084        window: &mut Window,
20085        cx: &mut Context<Self>,
20086    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20087        let snapshot = self.snapshot(window, cx);
20088        let buffer = &snapshot.buffer_snapshot;
20089        let start = buffer.anchor_before(0);
20090        let end = buffer.anchor_after(buffer.len());
20091        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20092    }
20093
20094    #[cfg(any(test, feature = "test-support"))]
20095    pub fn sorted_background_highlights_in_range(
20096        &self,
20097        search_range: Range<Anchor>,
20098        display_snapshot: &DisplaySnapshot,
20099        theme: &Theme,
20100    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20101        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20102        res.sort_by(|a, b| {
20103            a.0.start
20104                .cmp(&b.0.start)
20105                .then_with(|| a.0.end.cmp(&b.0.end))
20106                .then_with(|| a.1.cmp(&b.1))
20107        });
20108        res
20109    }
20110
20111    #[cfg(feature = "test-support")]
20112    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20113        let snapshot = self.buffer().read(cx).snapshot(cx);
20114
20115        let highlights = self
20116            .background_highlights
20117            .get(&HighlightKey::Type(TypeId::of::<
20118                items::BufferSearchHighlights,
20119            >()));
20120
20121        if let Some((_color, ranges)) = highlights {
20122            ranges
20123                .iter()
20124                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20125                .collect_vec()
20126        } else {
20127            vec![]
20128        }
20129    }
20130
20131    fn document_highlights_for_position<'a>(
20132        &'a self,
20133        position: Anchor,
20134        buffer: &'a MultiBufferSnapshot,
20135    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20136        let read_highlights = self
20137            .background_highlights
20138            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20139            .map(|h| &h.1);
20140        let write_highlights = self
20141            .background_highlights
20142            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20143            .map(|h| &h.1);
20144        let left_position = position.bias_left(buffer);
20145        let right_position = position.bias_right(buffer);
20146        read_highlights
20147            .into_iter()
20148            .chain(write_highlights)
20149            .flat_map(move |ranges| {
20150                let start_ix = match ranges.binary_search_by(|probe| {
20151                    let cmp = probe.end.cmp(&left_position, buffer);
20152                    if cmp.is_ge() {
20153                        Ordering::Greater
20154                    } else {
20155                        Ordering::Less
20156                    }
20157                }) {
20158                    Ok(i) | Err(i) => i,
20159                };
20160
20161                ranges[start_ix..]
20162                    .iter()
20163                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20164            })
20165    }
20166
20167    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20168        self.background_highlights
20169            .get(&HighlightKey::Type(TypeId::of::<T>()))
20170            .is_some_and(|(_, highlights)| !highlights.is_empty())
20171    }
20172
20173    /// Returns all background highlights for a given range.
20174    ///
20175    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20176    pub fn background_highlights_in_range(
20177        &self,
20178        search_range: Range<Anchor>,
20179        display_snapshot: &DisplaySnapshot,
20180        theme: &Theme,
20181    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20182        let mut results = Vec::new();
20183        for (color_fetcher, ranges) in self.background_highlights.values() {
20184            let color = color_fetcher(theme);
20185            let start_ix = match ranges.binary_search_by(|probe| {
20186                let cmp = probe
20187                    .end
20188                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20189                if cmp.is_gt() {
20190                    Ordering::Greater
20191                } else {
20192                    Ordering::Less
20193                }
20194            }) {
20195                Ok(i) | Err(i) => i,
20196            };
20197            for range in &ranges[start_ix..] {
20198                if range
20199                    .start
20200                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20201                    .is_ge()
20202                {
20203                    break;
20204                }
20205
20206                let start = range.start.to_display_point(display_snapshot);
20207                let end = range.end.to_display_point(display_snapshot);
20208                results.push((start..end, color))
20209            }
20210        }
20211        results
20212    }
20213
20214    pub fn gutter_highlights_in_range(
20215        &self,
20216        search_range: Range<Anchor>,
20217        display_snapshot: &DisplaySnapshot,
20218        cx: &App,
20219    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20220        let mut results = Vec::new();
20221        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20222            let color = color_fetcher(cx);
20223            let start_ix = match ranges.binary_search_by(|probe| {
20224                let cmp = probe
20225                    .end
20226                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20227                if cmp.is_gt() {
20228                    Ordering::Greater
20229                } else {
20230                    Ordering::Less
20231                }
20232            }) {
20233                Ok(i) | Err(i) => i,
20234            };
20235            for range in &ranges[start_ix..] {
20236                if range
20237                    .start
20238                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20239                    .is_ge()
20240                {
20241                    break;
20242                }
20243
20244                let start = range.start.to_display_point(display_snapshot);
20245                let end = range.end.to_display_point(display_snapshot);
20246                results.push((start..end, color))
20247            }
20248        }
20249        results
20250    }
20251
20252    /// Get the text ranges corresponding to the redaction query
20253    pub fn redacted_ranges(
20254        &self,
20255        search_range: Range<Anchor>,
20256        display_snapshot: &DisplaySnapshot,
20257        cx: &App,
20258    ) -> Vec<Range<DisplayPoint>> {
20259        display_snapshot
20260            .buffer_snapshot
20261            .redacted_ranges(search_range, |file| {
20262                if let Some(file) = file {
20263                    file.is_private()
20264                        && EditorSettings::get(
20265                            Some(SettingsLocation {
20266                                worktree_id: file.worktree_id(cx),
20267                                path: file.path().as_ref(),
20268                            }),
20269                            cx,
20270                        )
20271                        .redact_private_values
20272                } else {
20273                    false
20274                }
20275            })
20276            .map(|range| {
20277                range.start.to_display_point(display_snapshot)
20278                    ..range.end.to_display_point(display_snapshot)
20279            })
20280            .collect()
20281    }
20282
20283    pub fn highlight_text_key<T: 'static>(
20284        &mut self,
20285        key: usize,
20286        ranges: Vec<Range<Anchor>>,
20287        style: HighlightStyle,
20288        cx: &mut Context<Self>,
20289    ) {
20290        self.display_map.update(cx, |map, _| {
20291            map.highlight_text(
20292                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20293                ranges,
20294                style,
20295            );
20296        });
20297        cx.notify();
20298    }
20299
20300    pub fn highlight_text<T: 'static>(
20301        &mut self,
20302        ranges: Vec<Range<Anchor>>,
20303        style: HighlightStyle,
20304        cx: &mut Context<Self>,
20305    ) {
20306        self.display_map.update(cx, |map, _| {
20307            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20308        });
20309        cx.notify();
20310    }
20311
20312    pub(crate) fn highlight_inlays<T: 'static>(
20313        &mut self,
20314        highlights: Vec<InlayHighlight>,
20315        style: HighlightStyle,
20316        cx: &mut Context<Self>,
20317    ) {
20318        self.display_map.update(cx, |map, _| {
20319            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20320        });
20321        cx.notify();
20322    }
20323
20324    pub fn text_highlights<'a, T: 'static>(
20325        &'a self,
20326        cx: &'a App,
20327    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20328        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20329    }
20330
20331    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20332        let cleared = self
20333            .display_map
20334            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20335        if cleared {
20336            cx.notify();
20337        }
20338    }
20339
20340    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20341        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20342            && self.focus_handle.is_focused(window)
20343    }
20344
20345    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20346        self.show_cursor_when_unfocused = is_enabled;
20347        cx.notify();
20348    }
20349
20350    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20351        cx.notify();
20352    }
20353
20354    fn on_debug_session_event(
20355        &mut self,
20356        _session: Entity<Session>,
20357        event: &SessionEvent,
20358        cx: &mut Context<Self>,
20359    ) {
20360        if let SessionEvent::InvalidateInlineValue = event {
20361            self.refresh_inline_values(cx);
20362        }
20363    }
20364
20365    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20366        let Some(project) = self.project.clone() else {
20367            return;
20368        };
20369
20370        if !self.inline_value_cache.enabled {
20371            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20372            self.splice_inlays(&inlays, Vec::new(), cx);
20373            return;
20374        }
20375
20376        let current_execution_position = self
20377            .highlighted_rows
20378            .get(&TypeId::of::<ActiveDebugLine>())
20379            .and_then(|lines| lines.last().map(|line| line.range.end));
20380
20381        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20382            let inline_values = editor
20383                .update(cx, |editor, cx| {
20384                    let Some(current_execution_position) = current_execution_position else {
20385                        return Some(Task::ready(Ok(Vec::new())));
20386                    };
20387
20388                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20389                        let snapshot = buffer.snapshot(cx);
20390
20391                        let excerpt = snapshot.excerpt_containing(
20392                            current_execution_position..current_execution_position,
20393                        )?;
20394
20395                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20396                    })?;
20397
20398                    let range =
20399                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20400
20401                    project.inline_values(buffer, range, cx)
20402                })
20403                .ok()
20404                .flatten()?
20405                .await
20406                .context("refreshing debugger inlays")
20407                .log_err()?;
20408
20409            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20410
20411            for (buffer_id, inline_value) in inline_values
20412                .into_iter()
20413                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20414            {
20415                buffer_inline_values
20416                    .entry(buffer_id)
20417                    .or_default()
20418                    .push(inline_value);
20419            }
20420
20421            editor
20422                .update(cx, |editor, cx| {
20423                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20424                    let mut new_inlays = Vec::default();
20425
20426                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20427                        let buffer_id = buffer_snapshot.remote_id();
20428                        buffer_inline_values
20429                            .get(&buffer_id)
20430                            .into_iter()
20431                            .flatten()
20432                            .for_each(|hint| {
20433                                let inlay = Inlay::debugger(
20434                                    post_inc(&mut editor.next_inlay_id),
20435                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20436                                    hint.text(),
20437                                );
20438                                if !inlay.text.chars().contains(&'\n') {
20439                                    new_inlays.push(inlay);
20440                                }
20441                            });
20442                    }
20443
20444                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20445                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20446
20447                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20448                })
20449                .ok()?;
20450            Some(())
20451        });
20452    }
20453
20454    fn on_buffer_event(
20455        &mut self,
20456        multibuffer: &Entity<MultiBuffer>,
20457        event: &multi_buffer::Event,
20458        window: &mut Window,
20459        cx: &mut Context<Self>,
20460    ) {
20461        match event {
20462            multi_buffer::Event::Edited {
20463                singleton_buffer_edited,
20464                edited_buffer,
20465            } => {
20466                self.scrollbar_marker_state.dirty = true;
20467                self.active_indent_guides_state.dirty = true;
20468                self.refresh_active_diagnostics(cx);
20469                self.refresh_code_actions(window, cx);
20470                self.refresh_selected_text_highlights(true, window, cx);
20471                self.refresh_single_line_folds(window, cx);
20472                refresh_matching_bracket_highlights(self, window, cx);
20473                if self.has_active_edit_prediction() {
20474                    self.update_visible_edit_prediction(window, cx);
20475                }
20476                if let Some(project) = self.project.as_ref()
20477                    && let Some(edited_buffer) = edited_buffer
20478                {
20479                    project.update(cx, |project, cx| {
20480                        self.registered_buffers
20481                            .entry(edited_buffer.read(cx).remote_id())
20482                            .or_insert_with(|| {
20483                                project.register_buffer_with_language_servers(edited_buffer, cx)
20484                            });
20485                    });
20486                }
20487                cx.emit(EditorEvent::BufferEdited);
20488                cx.emit(SearchEvent::MatchesInvalidated);
20489
20490                if let Some(buffer) = edited_buffer {
20491                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20492                }
20493
20494                if *singleton_buffer_edited {
20495                    if let Some(buffer) = edited_buffer
20496                        && buffer.read(cx).file().is_none()
20497                    {
20498                        cx.emit(EditorEvent::TitleChanged);
20499                    }
20500                    if let Some(project) = &self.project {
20501                        #[allow(clippy::mutable_key_type)]
20502                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20503                            multibuffer
20504                                .all_buffers()
20505                                .into_iter()
20506                                .filter_map(|buffer| {
20507                                    buffer.update(cx, |buffer, cx| {
20508                                        let language = buffer.language()?;
20509                                        let should_discard = project.update(cx, |project, cx| {
20510                                            project.is_local()
20511                                                && !project.has_language_servers_for(buffer, cx)
20512                                        });
20513                                        should_discard.not().then_some(language.clone())
20514                                    })
20515                                })
20516                                .collect::<HashSet<_>>()
20517                        });
20518                        if !languages_affected.is_empty() {
20519                            self.refresh_inlay_hints(
20520                                InlayHintRefreshReason::BufferEdited(languages_affected),
20521                                cx,
20522                            );
20523                        }
20524                    }
20525                }
20526
20527                let Some(project) = &self.project else { return };
20528                let (telemetry, is_via_ssh) = {
20529                    let project = project.read(cx);
20530                    let telemetry = project.client().telemetry().clone();
20531                    let is_via_ssh = project.is_via_remote_server();
20532                    (telemetry, is_via_ssh)
20533                };
20534                refresh_linked_ranges(self, window, cx);
20535                telemetry.log_edit_event("editor", is_via_ssh);
20536            }
20537            multi_buffer::Event::ExcerptsAdded {
20538                buffer,
20539                predecessor,
20540                excerpts,
20541            } => {
20542                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20543                let buffer_id = buffer.read(cx).remote_id();
20544                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20545                    && let Some(project) = &self.project
20546                {
20547                    update_uncommitted_diff_for_buffer(
20548                        cx.entity(),
20549                        project,
20550                        [buffer.clone()],
20551                        self.buffer.clone(),
20552                        cx,
20553                    )
20554                    .detach();
20555                }
20556                if self.active_diagnostics != ActiveDiagnostic::All {
20557                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20558                }
20559                cx.emit(EditorEvent::ExcerptsAdded {
20560                    buffer: buffer.clone(),
20561                    predecessor: *predecessor,
20562                    excerpts: excerpts.clone(),
20563                });
20564                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20565            }
20566            multi_buffer::Event::ExcerptsRemoved {
20567                ids,
20568                removed_buffer_ids,
20569            } => {
20570                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20571                let buffer = self.buffer.read(cx);
20572                self.registered_buffers
20573                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20574                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20575                cx.emit(EditorEvent::ExcerptsRemoved {
20576                    ids: ids.clone(),
20577                    removed_buffer_ids: removed_buffer_ids.clone(),
20578                });
20579            }
20580            multi_buffer::Event::ExcerptsEdited {
20581                excerpt_ids,
20582                buffer_ids,
20583            } => {
20584                self.display_map.update(cx, |map, cx| {
20585                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20586                });
20587                cx.emit(EditorEvent::ExcerptsEdited {
20588                    ids: excerpt_ids.clone(),
20589                });
20590            }
20591            multi_buffer::Event::ExcerptsExpanded { ids } => {
20592                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20593                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20594            }
20595            multi_buffer::Event::Reparsed(buffer_id) => {
20596                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20597                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20598
20599                cx.emit(EditorEvent::Reparsed(*buffer_id));
20600            }
20601            multi_buffer::Event::DiffHunksToggled => {
20602                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20603            }
20604            multi_buffer::Event::LanguageChanged(buffer_id) => {
20605                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20606                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20607                cx.emit(EditorEvent::Reparsed(*buffer_id));
20608                cx.notify();
20609            }
20610            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20611            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20612            multi_buffer::Event::FileHandleChanged
20613            | multi_buffer::Event::Reloaded
20614            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20615            multi_buffer::Event::DiagnosticsUpdated => {
20616                self.update_diagnostics_state(window, cx);
20617            }
20618            _ => {}
20619        };
20620    }
20621
20622    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20623        if !self.diagnostics_enabled() {
20624            return;
20625        }
20626        self.refresh_active_diagnostics(cx);
20627        self.refresh_inline_diagnostics(true, window, cx);
20628        self.scrollbar_marker_state.dirty = true;
20629        cx.notify();
20630    }
20631
20632    pub fn start_temporary_diff_override(&mut self) {
20633        self.load_diff_task.take();
20634        self.temporary_diff_override = true;
20635    }
20636
20637    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20638        self.temporary_diff_override = false;
20639        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20640        self.buffer.update(cx, |buffer, cx| {
20641            buffer.set_all_diff_hunks_collapsed(cx);
20642        });
20643
20644        if let Some(project) = self.project.clone() {
20645            self.load_diff_task = Some(
20646                update_uncommitted_diff_for_buffer(
20647                    cx.entity(),
20648                    &project,
20649                    self.buffer.read(cx).all_buffers(),
20650                    self.buffer.clone(),
20651                    cx,
20652                )
20653                .shared(),
20654            );
20655        }
20656    }
20657
20658    fn on_display_map_changed(
20659        &mut self,
20660        _: Entity<DisplayMap>,
20661        _: &mut Window,
20662        cx: &mut Context<Self>,
20663    ) {
20664        cx.notify();
20665    }
20666
20667    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20668        if self.diagnostics_enabled() {
20669            let new_severity = EditorSettings::get_global(cx)
20670                .diagnostics_max_severity
20671                .unwrap_or(DiagnosticSeverity::Hint);
20672            self.set_max_diagnostics_severity(new_severity, cx);
20673        }
20674        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20675        self.update_edit_prediction_settings(cx);
20676        self.refresh_edit_prediction(true, false, window, cx);
20677        self.refresh_inline_values(cx);
20678        self.refresh_inlay_hints(
20679            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20680                self.selections.newest_anchor().head(),
20681                &self.buffer.read(cx).snapshot(cx),
20682                cx,
20683            )),
20684            cx,
20685        );
20686
20687        let old_cursor_shape = self.cursor_shape;
20688        let old_show_breadcrumbs = self.show_breadcrumbs;
20689
20690        {
20691            let editor_settings = EditorSettings::get_global(cx);
20692            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20693            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20694            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20695            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20696        }
20697
20698        if old_cursor_shape != self.cursor_shape {
20699            cx.emit(EditorEvent::CursorShapeChanged);
20700        }
20701
20702        if old_show_breadcrumbs != self.show_breadcrumbs {
20703            cx.emit(EditorEvent::BreadcrumbsChanged);
20704        }
20705
20706        let project_settings = ProjectSettings::get_global(cx);
20707        self.serialize_dirty_buffers =
20708            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20709
20710        if self.mode.is_full() {
20711            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20712            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20713            if self.show_inline_diagnostics != show_inline_diagnostics {
20714                self.show_inline_diagnostics = show_inline_diagnostics;
20715                self.refresh_inline_diagnostics(false, window, cx);
20716            }
20717
20718            if self.git_blame_inline_enabled != inline_blame_enabled {
20719                self.toggle_git_blame_inline_internal(false, window, cx);
20720            }
20721
20722            let minimap_settings = EditorSettings::get_global(cx).minimap;
20723            if self.minimap_visibility != MinimapVisibility::Disabled {
20724                if self.minimap_visibility.settings_visibility()
20725                    != minimap_settings.minimap_enabled()
20726                {
20727                    self.set_minimap_visibility(
20728                        MinimapVisibility::for_mode(self.mode(), cx),
20729                        window,
20730                        cx,
20731                    );
20732                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20733                    minimap_entity.update(cx, |minimap_editor, cx| {
20734                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20735                    })
20736                }
20737            }
20738        }
20739
20740        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20741            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20742        }) {
20743            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20744                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20745            }
20746            self.refresh_colors(false, None, window, cx);
20747        }
20748
20749        cx.notify();
20750    }
20751
20752    pub fn set_searchable(&mut self, searchable: bool) {
20753        self.searchable = searchable;
20754    }
20755
20756    pub fn searchable(&self) -> bool {
20757        self.searchable
20758    }
20759
20760    fn open_proposed_changes_editor(
20761        &mut self,
20762        _: &OpenProposedChangesEditor,
20763        window: &mut Window,
20764        cx: &mut Context<Self>,
20765    ) {
20766        let Some(workspace) = self.workspace() else {
20767            cx.propagate();
20768            return;
20769        };
20770
20771        let selections = self.selections.all::<usize>(cx);
20772        let multi_buffer = self.buffer.read(cx);
20773        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20774        let mut new_selections_by_buffer = HashMap::default();
20775        for selection in selections {
20776            for (buffer, range, _) in
20777                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20778            {
20779                let mut range = range.to_point(buffer);
20780                range.start.column = 0;
20781                range.end.column = buffer.line_len(range.end.row);
20782                new_selections_by_buffer
20783                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20784                    .or_insert(Vec::new())
20785                    .push(range)
20786            }
20787        }
20788
20789        let proposed_changes_buffers = new_selections_by_buffer
20790            .into_iter()
20791            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20792            .collect::<Vec<_>>();
20793        let proposed_changes_editor = cx.new(|cx| {
20794            ProposedChangesEditor::new(
20795                "Proposed changes",
20796                proposed_changes_buffers,
20797                self.project.clone(),
20798                window,
20799                cx,
20800            )
20801        });
20802
20803        window.defer(cx, move |window, cx| {
20804            workspace.update(cx, |workspace, cx| {
20805                workspace.active_pane().update(cx, |pane, cx| {
20806                    pane.add_item(
20807                        Box::new(proposed_changes_editor),
20808                        true,
20809                        true,
20810                        None,
20811                        window,
20812                        cx,
20813                    );
20814                });
20815            });
20816        });
20817    }
20818
20819    pub fn open_excerpts_in_split(
20820        &mut self,
20821        _: &OpenExcerptsSplit,
20822        window: &mut Window,
20823        cx: &mut Context<Self>,
20824    ) {
20825        self.open_excerpts_common(None, true, window, cx)
20826    }
20827
20828    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20829        self.open_excerpts_common(None, false, window, cx)
20830    }
20831
20832    fn open_excerpts_common(
20833        &mut self,
20834        jump_data: Option<JumpData>,
20835        split: bool,
20836        window: &mut Window,
20837        cx: &mut Context<Self>,
20838    ) {
20839        let Some(workspace) = self.workspace() else {
20840            cx.propagate();
20841            return;
20842        };
20843
20844        if self.buffer.read(cx).is_singleton() {
20845            cx.propagate();
20846            return;
20847        }
20848
20849        let mut new_selections_by_buffer = HashMap::default();
20850        match &jump_data {
20851            Some(JumpData::MultiBufferPoint {
20852                excerpt_id,
20853                position,
20854                anchor,
20855                line_offset_from_top,
20856            }) => {
20857                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20858                if let Some(buffer) = multi_buffer_snapshot
20859                    .buffer_id_for_excerpt(*excerpt_id)
20860                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20861                {
20862                    let buffer_snapshot = buffer.read(cx).snapshot();
20863                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20864                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20865                    } else {
20866                        buffer_snapshot.clip_point(*position, Bias::Left)
20867                    };
20868                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20869                    new_selections_by_buffer.insert(
20870                        buffer,
20871                        (
20872                            vec![jump_to_offset..jump_to_offset],
20873                            Some(*line_offset_from_top),
20874                        ),
20875                    );
20876                }
20877            }
20878            Some(JumpData::MultiBufferRow {
20879                row,
20880                line_offset_from_top,
20881            }) => {
20882                let point = MultiBufferPoint::new(row.0, 0);
20883                if let Some((buffer, buffer_point, _)) =
20884                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20885                {
20886                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20887                    new_selections_by_buffer
20888                        .entry(buffer)
20889                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20890                        .0
20891                        .push(buffer_offset..buffer_offset)
20892                }
20893            }
20894            None => {
20895                let selections = self.selections.all::<usize>(cx);
20896                let multi_buffer = self.buffer.read(cx);
20897                for selection in selections {
20898                    for (snapshot, range, _, anchor) in multi_buffer
20899                        .snapshot(cx)
20900                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20901                    {
20902                        if let Some(anchor) = anchor {
20903                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20904                            else {
20905                                continue;
20906                            };
20907                            let offset = text::ToOffset::to_offset(
20908                                &anchor.text_anchor,
20909                                &buffer_handle.read(cx).snapshot(),
20910                            );
20911                            let range = offset..offset;
20912                            new_selections_by_buffer
20913                                .entry(buffer_handle)
20914                                .or_insert((Vec::new(), None))
20915                                .0
20916                                .push(range)
20917                        } else {
20918                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20919                            else {
20920                                continue;
20921                            };
20922                            new_selections_by_buffer
20923                                .entry(buffer_handle)
20924                                .or_insert((Vec::new(), None))
20925                                .0
20926                                .push(range)
20927                        }
20928                    }
20929                }
20930            }
20931        }
20932
20933        new_selections_by_buffer
20934            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20935
20936        if new_selections_by_buffer.is_empty() {
20937            return;
20938        }
20939
20940        // We defer the pane interaction because we ourselves are a workspace item
20941        // and activating a new item causes the pane to call a method on us reentrantly,
20942        // which panics if we're on the stack.
20943        window.defer(cx, move |window, cx| {
20944            workspace.update(cx, |workspace, cx| {
20945                let pane = if split {
20946                    workspace.adjacent_pane(window, cx)
20947                } else {
20948                    workspace.active_pane().clone()
20949                };
20950
20951                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20952                    let editor = buffer
20953                        .read(cx)
20954                        .file()
20955                        .is_none()
20956                        .then(|| {
20957                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20958                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20959                            // Instead, we try to activate the existing editor in the pane first.
20960                            let (editor, pane_item_index) =
20961                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20962                                    let editor = item.downcast::<Editor>()?;
20963                                    let singleton_buffer =
20964                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20965                                    if singleton_buffer == buffer {
20966                                        Some((editor, i))
20967                                    } else {
20968                                        None
20969                                    }
20970                                })?;
20971                            pane.update(cx, |pane, cx| {
20972                                pane.activate_item(pane_item_index, true, true, window, cx)
20973                            });
20974                            Some(editor)
20975                        })
20976                        .flatten()
20977                        .unwrap_or_else(|| {
20978                            workspace.open_project_item::<Self>(
20979                                pane.clone(),
20980                                buffer,
20981                                true,
20982                                true,
20983                                window,
20984                                cx,
20985                            )
20986                        });
20987
20988                    editor.update(cx, |editor, cx| {
20989                        let autoscroll = match scroll_offset {
20990                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20991                            None => Autoscroll::newest(),
20992                        };
20993                        let nav_history = editor.nav_history.take();
20994                        editor.change_selections(
20995                            SelectionEffects::scroll(autoscroll),
20996                            window,
20997                            cx,
20998                            |s| {
20999                                s.select_ranges(ranges);
21000                            },
21001                        );
21002                        editor.nav_history = nav_history;
21003                    });
21004                }
21005            })
21006        });
21007    }
21008
21009    // For now, don't allow opening excerpts in buffers that aren't backed by
21010    // regular project files.
21011    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21012        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21013    }
21014
21015    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21016        let snapshot = self.buffer.read(cx).read(cx);
21017        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21018        Some(
21019            ranges
21020                .iter()
21021                .map(move |range| {
21022                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21023                })
21024                .collect(),
21025        )
21026    }
21027
21028    fn selection_replacement_ranges(
21029        &self,
21030        range: Range<OffsetUtf16>,
21031        cx: &mut App,
21032    ) -> Vec<Range<OffsetUtf16>> {
21033        let selections = self.selections.all::<OffsetUtf16>(cx);
21034        let newest_selection = selections
21035            .iter()
21036            .max_by_key(|selection| selection.id)
21037            .unwrap();
21038        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21039        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21040        let snapshot = self.buffer.read(cx).read(cx);
21041        selections
21042            .into_iter()
21043            .map(|mut selection| {
21044                selection.start.0 =
21045                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21046                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21047                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21048                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21049            })
21050            .collect()
21051    }
21052
21053    fn report_editor_event(
21054        &self,
21055        reported_event: ReportEditorEvent,
21056        file_extension: Option<String>,
21057        cx: &App,
21058    ) {
21059        if cfg!(any(test, feature = "test-support")) {
21060            return;
21061        }
21062
21063        let Some(project) = &self.project else { return };
21064
21065        // If None, we are in a file without an extension
21066        let file = self
21067            .buffer
21068            .read(cx)
21069            .as_singleton()
21070            .and_then(|b| b.read(cx).file());
21071        let file_extension = file_extension.or(file
21072            .as_ref()
21073            .and_then(|file| Path::new(file.file_name(cx)).extension())
21074            .and_then(|e| e.to_str())
21075            .map(|a| a.to_string()));
21076
21077        let vim_mode = vim_enabled(cx);
21078
21079        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21080        let copilot_enabled = edit_predictions_provider
21081            == language::language_settings::EditPredictionProvider::Copilot;
21082        let copilot_enabled_for_language = self
21083            .buffer
21084            .read(cx)
21085            .language_settings(cx)
21086            .show_edit_predictions;
21087
21088        let project = project.read(cx);
21089        let event_type = reported_event.event_type();
21090
21091        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21092            telemetry::event!(
21093                event_type,
21094                type = if auto_saved {"autosave"} else {"manual"},
21095                file_extension,
21096                vim_mode,
21097                copilot_enabled,
21098                copilot_enabled_for_language,
21099                edit_predictions_provider,
21100                is_via_ssh = project.is_via_remote_server(),
21101            );
21102        } else {
21103            telemetry::event!(
21104                event_type,
21105                file_extension,
21106                vim_mode,
21107                copilot_enabled,
21108                copilot_enabled_for_language,
21109                edit_predictions_provider,
21110                is_via_ssh = project.is_via_remote_server(),
21111            );
21112        };
21113    }
21114
21115    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21116    /// with each line being an array of {text, highlight} objects.
21117    fn copy_highlight_json(
21118        &mut self,
21119        _: &CopyHighlightJson,
21120        window: &mut Window,
21121        cx: &mut Context<Self>,
21122    ) {
21123        #[derive(Serialize)]
21124        struct Chunk<'a> {
21125            text: String,
21126            highlight: Option<&'a str>,
21127        }
21128
21129        let snapshot = self.buffer.read(cx).snapshot(cx);
21130        let range = self
21131            .selected_text_range(false, window, cx)
21132            .and_then(|selection| {
21133                if selection.range.is_empty() {
21134                    None
21135                } else {
21136                    Some(selection.range)
21137                }
21138            })
21139            .unwrap_or_else(|| 0..snapshot.len());
21140
21141        let chunks = snapshot.chunks(range, true);
21142        let mut lines = Vec::new();
21143        let mut line: VecDeque<Chunk> = VecDeque::new();
21144
21145        let Some(style) = self.style.as_ref() else {
21146            return;
21147        };
21148
21149        for chunk in chunks {
21150            let highlight = chunk
21151                .syntax_highlight_id
21152                .and_then(|id| id.name(&style.syntax));
21153            let mut chunk_lines = chunk.text.split('\n').peekable();
21154            while let Some(text) = chunk_lines.next() {
21155                let mut merged_with_last_token = false;
21156                if let Some(last_token) = line.back_mut()
21157                    && last_token.highlight == highlight
21158                {
21159                    last_token.text.push_str(text);
21160                    merged_with_last_token = true;
21161                }
21162
21163                if !merged_with_last_token {
21164                    line.push_back(Chunk {
21165                        text: text.into(),
21166                        highlight,
21167                    });
21168                }
21169
21170                if chunk_lines.peek().is_some() {
21171                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21172                        line.pop_front();
21173                    }
21174                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21175                        line.pop_back();
21176                    }
21177
21178                    lines.push(mem::take(&mut line));
21179                }
21180            }
21181        }
21182
21183        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21184            return;
21185        };
21186        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21187    }
21188
21189    pub fn open_context_menu(
21190        &mut self,
21191        _: &OpenContextMenu,
21192        window: &mut Window,
21193        cx: &mut Context<Self>,
21194    ) {
21195        self.request_autoscroll(Autoscroll::newest(), cx);
21196        let position = self.selections.newest_display(cx).start;
21197        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21198    }
21199
21200    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21201        &self.inlay_hint_cache
21202    }
21203
21204    pub fn replay_insert_event(
21205        &mut self,
21206        text: &str,
21207        relative_utf16_range: Option<Range<isize>>,
21208        window: &mut Window,
21209        cx: &mut Context<Self>,
21210    ) {
21211        if !self.input_enabled {
21212            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21213            return;
21214        }
21215        if let Some(relative_utf16_range) = relative_utf16_range {
21216            let selections = self.selections.all::<OffsetUtf16>(cx);
21217            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21218                let new_ranges = selections.into_iter().map(|range| {
21219                    let start = OffsetUtf16(
21220                        range
21221                            .head()
21222                            .0
21223                            .saturating_add_signed(relative_utf16_range.start),
21224                    );
21225                    let end = OffsetUtf16(
21226                        range
21227                            .head()
21228                            .0
21229                            .saturating_add_signed(relative_utf16_range.end),
21230                    );
21231                    start..end
21232                });
21233                s.select_ranges(new_ranges);
21234            });
21235        }
21236
21237        self.handle_input(text, window, cx);
21238    }
21239
21240    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21241        let Some(provider) = self.semantics_provider.as_ref() else {
21242            return false;
21243        };
21244
21245        let mut supports = false;
21246        self.buffer().update(cx, |this, cx| {
21247            this.for_each_buffer(|buffer| {
21248                supports |= provider.supports_inlay_hints(buffer, cx);
21249            });
21250        });
21251
21252        supports
21253    }
21254
21255    pub fn is_focused(&self, window: &Window) -> bool {
21256        self.focus_handle.is_focused(window)
21257    }
21258
21259    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21260        cx.emit(EditorEvent::Focused);
21261
21262        if let Some(descendant) = self
21263            .last_focused_descendant
21264            .take()
21265            .and_then(|descendant| descendant.upgrade())
21266        {
21267            window.focus(&descendant);
21268        } else {
21269            if let Some(blame) = self.blame.as_ref() {
21270                blame.update(cx, GitBlame::focus)
21271            }
21272
21273            self.blink_manager.update(cx, BlinkManager::enable);
21274            self.show_cursor_names(window, cx);
21275            self.buffer.update(cx, |buffer, cx| {
21276                buffer.finalize_last_transaction(cx);
21277                if self.leader_id.is_none() {
21278                    buffer.set_active_selections(
21279                        &self.selections.disjoint_anchors(),
21280                        self.selections.line_mode,
21281                        self.cursor_shape,
21282                        cx,
21283                    );
21284                }
21285            });
21286        }
21287    }
21288
21289    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21290        cx.emit(EditorEvent::FocusedIn)
21291    }
21292
21293    fn handle_focus_out(
21294        &mut self,
21295        event: FocusOutEvent,
21296        _window: &mut Window,
21297        cx: &mut Context<Self>,
21298    ) {
21299        if event.blurred != self.focus_handle {
21300            self.last_focused_descendant = Some(event.blurred);
21301        }
21302        self.selection_drag_state = SelectionDragState::None;
21303        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21304    }
21305
21306    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21307        self.blink_manager.update(cx, BlinkManager::disable);
21308        self.buffer
21309            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21310
21311        if let Some(blame) = self.blame.as_ref() {
21312            blame.update(cx, GitBlame::blur)
21313        }
21314        if !self.hover_state.focused(window, cx) {
21315            hide_hover(self, cx);
21316        }
21317        if !self
21318            .context_menu
21319            .borrow()
21320            .as_ref()
21321            .is_some_and(|context_menu| context_menu.focused(window, cx))
21322        {
21323            self.hide_context_menu(window, cx);
21324        }
21325        self.discard_edit_prediction(false, cx);
21326        cx.emit(EditorEvent::Blurred);
21327        cx.notify();
21328    }
21329
21330    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21331        let mut pending: String = window
21332            .pending_input_keystrokes()
21333            .into_iter()
21334            .flatten()
21335            .filter_map(|keystroke| {
21336                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21337                    keystroke.key_char.clone()
21338                } else {
21339                    None
21340                }
21341            })
21342            .collect();
21343
21344        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21345            pending = "".to_string();
21346        }
21347
21348        let existing_pending = self
21349            .text_highlights::<PendingInput>(cx)
21350            .map(|(_, ranges)| ranges.to_vec());
21351        if existing_pending.is_none() && pending.is_empty() {
21352            return;
21353        }
21354        let transaction =
21355            self.transact(window, cx, |this, window, cx| {
21356                let selections = this.selections.all::<usize>(cx);
21357                let edits = selections
21358                    .iter()
21359                    .map(|selection| (selection.end..selection.end, pending.clone()));
21360                this.edit(edits, cx);
21361                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21362                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21363                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21364                    }));
21365                });
21366                if let Some(existing_ranges) = existing_pending {
21367                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21368                    this.edit(edits, cx);
21369                }
21370            });
21371
21372        let snapshot = self.snapshot(window, cx);
21373        let ranges = self
21374            .selections
21375            .all::<usize>(cx)
21376            .into_iter()
21377            .map(|selection| {
21378                snapshot.buffer_snapshot.anchor_after(selection.end)
21379                    ..snapshot
21380                        .buffer_snapshot
21381                        .anchor_before(selection.end + pending.len())
21382            })
21383            .collect();
21384
21385        if pending.is_empty() {
21386            self.clear_highlights::<PendingInput>(cx);
21387        } else {
21388            self.highlight_text::<PendingInput>(
21389                ranges,
21390                HighlightStyle {
21391                    underline: Some(UnderlineStyle {
21392                        thickness: px(1.),
21393                        color: None,
21394                        wavy: false,
21395                    }),
21396                    ..Default::default()
21397                },
21398                cx,
21399            );
21400        }
21401
21402        self.ime_transaction = self.ime_transaction.or(transaction);
21403        if let Some(transaction) = self.ime_transaction {
21404            self.buffer.update(cx, |buffer, cx| {
21405                buffer.group_until_transaction(transaction, cx);
21406            });
21407        }
21408
21409        if self.text_highlights::<PendingInput>(cx).is_none() {
21410            self.ime_transaction.take();
21411        }
21412    }
21413
21414    pub fn register_action_renderer(
21415        &mut self,
21416        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21417    ) -> Subscription {
21418        let id = self.next_editor_action_id.post_inc();
21419        self.editor_actions
21420            .borrow_mut()
21421            .insert(id, Box::new(listener));
21422
21423        let editor_actions = self.editor_actions.clone();
21424        Subscription::new(move || {
21425            editor_actions.borrow_mut().remove(&id);
21426        })
21427    }
21428
21429    pub fn register_action<A: Action>(
21430        &mut self,
21431        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21432    ) -> Subscription {
21433        let id = self.next_editor_action_id.post_inc();
21434        let listener = Arc::new(listener);
21435        self.editor_actions.borrow_mut().insert(
21436            id,
21437            Box::new(move |_, window, _| {
21438                let listener = listener.clone();
21439                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21440                    let action = action.downcast_ref().unwrap();
21441                    if phase == DispatchPhase::Bubble {
21442                        listener(action, window, cx)
21443                    }
21444                })
21445            }),
21446        );
21447
21448        let editor_actions = self.editor_actions.clone();
21449        Subscription::new(move || {
21450            editor_actions.borrow_mut().remove(&id);
21451        })
21452    }
21453
21454    pub fn file_header_size(&self) -> u32 {
21455        FILE_HEADER_HEIGHT
21456    }
21457
21458    pub fn restore(
21459        &mut self,
21460        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21461        window: &mut Window,
21462        cx: &mut Context<Self>,
21463    ) {
21464        let workspace = self.workspace();
21465        let project = self.project();
21466        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21467            let mut tasks = Vec::new();
21468            for (buffer_id, changes) in revert_changes {
21469                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21470                    buffer.update(cx, |buffer, cx| {
21471                        buffer.edit(
21472                            changes
21473                                .into_iter()
21474                                .map(|(range, text)| (range, text.to_string())),
21475                            None,
21476                            cx,
21477                        );
21478                    });
21479
21480                    if let Some(project) =
21481                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21482                    {
21483                        project.update(cx, |project, cx| {
21484                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21485                        })
21486                    }
21487                }
21488            }
21489            tasks
21490        });
21491        cx.spawn_in(window, async move |_, cx| {
21492            for (buffer, task) in save_tasks {
21493                let result = task.await;
21494                if result.is_err() {
21495                    let Some(path) = buffer
21496                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21497                        .ok()
21498                    else {
21499                        continue;
21500                    };
21501                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21502                        let Some(task) = cx
21503                            .update_window_entity(workspace, |workspace, window, cx| {
21504                                workspace
21505                                    .open_path_preview(path, None, false, false, false, window, cx)
21506                            })
21507                            .ok()
21508                        else {
21509                            continue;
21510                        };
21511                        task.await.log_err();
21512                    }
21513                }
21514            }
21515        })
21516        .detach();
21517        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21518            selections.refresh()
21519        });
21520    }
21521
21522    pub fn to_pixel_point(
21523        &self,
21524        source: multi_buffer::Anchor,
21525        editor_snapshot: &EditorSnapshot,
21526        window: &mut Window,
21527    ) -> Option<gpui::Point<Pixels>> {
21528        let source_point = source.to_display_point(editor_snapshot);
21529        self.display_to_pixel_point(source_point, editor_snapshot, window)
21530    }
21531
21532    pub fn display_to_pixel_point(
21533        &self,
21534        source: DisplayPoint,
21535        editor_snapshot: &EditorSnapshot,
21536        window: &mut Window,
21537    ) -> Option<gpui::Point<Pixels>> {
21538        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21539        let text_layout_details = self.text_layout_details(window);
21540        let scroll_top = text_layout_details
21541            .scroll_anchor
21542            .scroll_position(editor_snapshot)
21543            .y;
21544
21545        if source.row().as_f32() < scroll_top.floor() {
21546            return None;
21547        }
21548        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21549        let source_y = line_height * (source.row().as_f32() - scroll_top);
21550        Some(gpui::Point::new(source_x, source_y))
21551    }
21552
21553    pub fn has_visible_completions_menu(&self) -> bool {
21554        !self.edit_prediction_preview_is_active()
21555            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21556                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21557            })
21558    }
21559
21560    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21561        if self.mode.is_minimap() {
21562            return;
21563        }
21564        self.addons
21565            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21566    }
21567
21568    pub fn unregister_addon<T: Addon>(&mut self) {
21569        self.addons.remove(&std::any::TypeId::of::<T>());
21570    }
21571
21572    pub fn addon<T: Addon>(&self) -> Option<&T> {
21573        let type_id = std::any::TypeId::of::<T>();
21574        self.addons
21575            .get(&type_id)
21576            .and_then(|item| item.to_any().downcast_ref::<T>())
21577    }
21578
21579    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21580        let type_id = std::any::TypeId::of::<T>();
21581        self.addons
21582            .get_mut(&type_id)
21583            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21584    }
21585
21586    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21587        let text_layout_details = self.text_layout_details(window);
21588        let style = &text_layout_details.editor_style;
21589        let font_id = window.text_system().resolve_font(&style.text.font());
21590        let font_size = style.text.font_size.to_pixels(window.rem_size());
21591        let line_height = style.text.line_height_in_pixels(window.rem_size());
21592        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21593        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21594
21595        CharacterDimensions {
21596            em_width,
21597            em_advance,
21598            line_height,
21599        }
21600    }
21601
21602    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21603        self.load_diff_task.clone()
21604    }
21605
21606    fn read_metadata_from_db(
21607        &mut self,
21608        item_id: u64,
21609        workspace_id: WorkspaceId,
21610        window: &mut Window,
21611        cx: &mut Context<Editor>,
21612    ) {
21613        if self.is_singleton(cx)
21614            && !self.mode.is_minimap()
21615            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21616        {
21617            let buffer_snapshot = OnceCell::new();
21618
21619            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21620                && !folds.is_empty()
21621            {
21622                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21623                self.fold_ranges(
21624                    folds
21625                        .into_iter()
21626                        .map(|(start, end)| {
21627                            snapshot.clip_offset(start, Bias::Left)
21628                                ..snapshot.clip_offset(end, Bias::Right)
21629                        })
21630                        .collect(),
21631                    false,
21632                    window,
21633                    cx,
21634                );
21635            }
21636
21637            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21638                && !selections.is_empty()
21639            {
21640                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21641                // skip adding the initial selection to selection history
21642                self.selection_history.mode = SelectionHistoryMode::Skipping;
21643                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21644                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21645                        snapshot.clip_offset(start, Bias::Left)
21646                            ..snapshot.clip_offset(end, Bias::Right)
21647                    }));
21648                });
21649                self.selection_history.mode = SelectionHistoryMode::Normal;
21650            };
21651        }
21652
21653        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21654    }
21655
21656    fn update_lsp_data(
21657        &mut self,
21658        ignore_cache: bool,
21659        for_buffer: Option<BufferId>,
21660        window: &mut Window,
21661        cx: &mut Context<'_, Self>,
21662    ) {
21663        self.pull_diagnostics(for_buffer, window, cx);
21664        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21665    }
21666}
21667
21668fn vim_enabled(cx: &App) -> bool {
21669    cx.global::<SettingsStore>()
21670        .raw_user_settings()
21671        .get("vim_mode")
21672        == Some(&serde_json::Value::Bool(true))
21673}
21674
21675fn process_completion_for_edit(
21676    completion: &Completion,
21677    intent: CompletionIntent,
21678    buffer: &Entity<Buffer>,
21679    cursor_position: &text::Anchor,
21680    cx: &mut Context<Editor>,
21681) -> CompletionEdit {
21682    let buffer = buffer.read(cx);
21683    let buffer_snapshot = buffer.snapshot();
21684    let (snippet, new_text) = if completion.is_snippet() {
21685        // Workaround for typescript language server issues so that methods don't expand within
21686        // strings and functions with type expressions. The previous point is used because the query
21687        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21688        let mut snippet_source = completion.new_text.clone();
21689        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21690        previous_point.column = previous_point.column.saturating_sub(1);
21691        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21692            && scope.prefers_label_for_snippet_in_completion()
21693            && let Some(label) = completion.label()
21694            && matches!(
21695                completion.kind(),
21696                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21697            )
21698        {
21699            snippet_source = label;
21700        }
21701        match Snippet::parse(&snippet_source).log_err() {
21702            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21703            None => (None, completion.new_text.clone()),
21704        }
21705    } else {
21706        (None, completion.new_text.clone())
21707    };
21708
21709    let mut range_to_replace = {
21710        let replace_range = &completion.replace_range;
21711        if let CompletionSource::Lsp {
21712            insert_range: Some(insert_range),
21713            ..
21714        } = &completion.source
21715        {
21716            debug_assert_eq!(
21717                insert_range.start, replace_range.start,
21718                "insert_range and replace_range should start at the same position"
21719            );
21720            debug_assert!(
21721                insert_range
21722                    .start
21723                    .cmp(cursor_position, &buffer_snapshot)
21724                    .is_le(),
21725                "insert_range should start before or at cursor position"
21726            );
21727            debug_assert!(
21728                replace_range
21729                    .start
21730                    .cmp(cursor_position, &buffer_snapshot)
21731                    .is_le(),
21732                "replace_range should start before or at cursor position"
21733            );
21734
21735            let should_replace = match intent {
21736                CompletionIntent::CompleteWithInsert => false,
21737                CompletionIntent::CompleteWithReplace => true,
21738                CompletionIntent::Complete | CompletionIntent::Compose => {
21739                    let insert_mode =
21740                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21741                            .completions
21742                            .lsp_insert_mode;
21743                    match insert_mode {
21744                        LspInsertMode::Insert => false,
21745                        LspInsertMode::Replace => true,
21746                        LspInsertMode::ReplaceSubsequence => {
21747                            let mut text_to_replace = buffer.chars_for_range(
21748                                buffer.anchor_before(replace_range.start)
21749                                    ..buffer.anchor_after(replace_range.end),
21750                            );
21751                            let mut current_needle = text_to_replace.next();
21752                            for haystack_ch in completion.label.text.chars() {
21753                                if let Some(needle_ch) = current_needle
21754                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21755                                {
21756                                    current_needle = text_to_replace.next();
21757                                }
21758                            }
21759                            current_needle.is_none()
21760                        }
21761                        LspInsertMode::ReplaceSuffix => {
21762                            if replace_range
21763                                .end
21764                                .cmp(cursor_position, &buffer_snapshot)
21765                                .is_gt()
21766                            {
21767                                let range_after_cursor = *cursor_position..replace_range.end;
21768                                let text_after_cursor = buffer
21769                                    .text_for_range(
21770                                        buffer.anchor_before(range_after_cursor.start)
21771                                            ..buffer.anchor_after(range_after_cursor.end),
21772                                    )
21773                                    .collect::<String>()
21774                                    .to_ascii_lowercase();
21775                                completion
21776                                    .label
21777                                    .text
21778                                    .to_ascii_lowercase()
21779                                    .ends_with(&text_after_cursor)
21780                            } else {
21781                                true
21782                            }
21783                        }
21784                    }
21785                }
21786            };
21787
21788            if should_replace {
21789                replace_range.clone()
21790            } else {
21791                insert_range.clone()
21792            }
21793        } else {
21794            replace_range.clone()
21795        }
21796    };
21797
21798    if range_to_replace
21799        .end
21800        .cmp(cursor_position, &buffer_snapshot)
21801        .is_lt()
21802    {
21803        range_to_replace.end = *cursor_position;
21804    }
21805
21806    CompletionEdit {
21807        new_text,
21808        replace_range: range_to_replace.to_offset(buffer),
21809        snippet,
21810    }
21811}
21812
21813struct CompletionEdit {
21814    new_text: String,
21815    replace_range: Range<usize>,
21816    snippet: Option<Snippet>,
21817}
21818
21819fn insert_extra_newline_brackets(
21820    buffer: &MultiBufferSnapshot,
21821    range: Range<usize>,
21822    language: &language::LanguageScope,
21823) -> bool {
21824    let leading_whitespace_len = buffer
21825        .reversed_chars_at(range.start)
21826        .take_while(|c| c.is_whitespace() && *c != '\n')
21827        .map(|c| c.len_utf8())
21828        .sum::<usize>();
21829    let trailing_whitespace_len = buffer
21830        .chars_at(range.end)
21831        .take_while(|c| c.is_whitespace() && *c != '\n')
21832        .map(|c| c.len_utf8())
21833        .sum::<usize>();
21834    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21835
21836    language.brackets().any(|(pair, enabled)| {
21837        let pair_start = pair.start.trim_end();
21838        let pair_end = pair.end.trim_start();
21839
21840        enabled
21841            && pair.newline
21842            && buffer.contains_str_at(range.end, pair_end)
21843            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21844    })
21845}
21846
21847fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21848    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21849        [(buffer, range, _)] => (*buffer, range.clone()),
21850        _ => return false,
21851    };
21852    let pair = {
21853        let mut result: Option<BracketMatch> = None;
21854
21855        for pair in buffer
21856            .all_bracket_ranges(range.clone())
21857            .filter(move |pair| {
21858                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21859            })
21860        {
21861            let len = pair.close_range.end - pair.open_range.start;
21862
21863            if let Some(existing) = &result {
21864                let existing_len = existing.close_range.end - existing.open_range.start;
21865                if len > existing_len {
21866                    continue;
21867                }
21868            }
21869
21870            result = Some(pair);
21871        }
21872
21873        result
21874    };
21875    let Some(pair) = pair else {
21876        return false;
21877    };
21878    pair.newline_only
21879        && buffer
21880            .chars_for_range(pair.open_range.end..range.start)
21881            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21882            .all(|c| c.is_whitespace() && c != '\n')
21883}
21884
21885fn update_uncommitted_diff_for_buffer(
21886    editor: Entity<Editor>,
21887    project: &Entity<Project>,
21888    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21889    buffer: Entity<MultiBuffer>,
21890    cx: &mut App,
21891) -> Task<()> {
21892    let mut tasks = Vec::new();
21893    project.update(cx, |project, cx| {
21894        for buffer in buffers {
21895            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21896                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21897            }
21898        }
21899    });
21900    cx.spawn(async move |cx| {
21901        let diffs = future::join_all(tasks).await;
21902        if editor
21903            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21904            .unwrap_or(false)
21905        {
21906            return;
21907        }
21908
21909        buffer
21910            .update(cx, |buffer, cx| {
21911                for diff in diffs.into_iter().flatten() {
21912                    buffer.add_diff(diff, cx);
21913                }
21914            })
21915            .ok();
21916    })
21917}
21918
21919fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21920    let tab_size = tab_size.get() as usize;
21921    let mut width = offset;
21922
21923    for ch in text.chars() {
21924        width += if ch == '\t' {
21925            tab_size - (width % tab_size)
21926        } else {
21927            1
21928        };
21929    }
21930
21931    width - offset
21932}
21933
21934#[cfg(test)]
21935mod tests {
21936    use super::*;
21937
21938    #[test]
21939    fn test_string_size_with_expanded_tabs() {
21940        let nz = |val| NonZeroU32::new(val).unwrap();
21941        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21942        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21943        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21944        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21945        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21946        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21947        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21948        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21949    }
21950}
21951
21952/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21953struct WordBreakingTokenizer<'a> {
21954    input: &'a str,
21955}
21956
21957impl<'a> WordBreakingTokenizer<'a> {
21958    fn new(input: &'a str) -> Self {
21959        Self { input }
21960    }
21961}
21962
21963fn is_char_ideographic(ch: char) -> bool {
21964    use unicode_script::Script::*;
21965    use unicode_script::UnicodeScript;
21966    matches!(ch.script(), Han | Tangut | Yi)
21967}
21968
21969fn is_grapheme_ideographic(text: &str) -> bool {
21970    text.chars().any(is_char_ideographic)
21971}
21972
21973fn is_grapheme_whitespace(text: &str) -> bool {
21974    text.chars().any(|x| x.is_whitespace())
21975}
21976
21977fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21978    text.chars()
21979        .next()
21980        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21981}
21982
21983#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21984enum WordBreakToken<'a> {
21985    Word { token: &'a str, grapheme_len: usize },
21986    InlineWhitespace { token: &'a str, grapheme_len: usize },
21987    Newline,
21988}
21989
21990impl<'a> Iterator for WordBreakingTokenizer<'a> {
21991    /// Yields a span, the count of graphemes in the token, and whether it was
21992    /// whitespace. Note that it also breaks at word boundaries.
21993    type Item = WordBreakToken<'a>;
21994
21995    fn next(&mut self) -> Option<Self::Item> {
21996        use unicode_segmentation::UnicodeSegmentation;
21997        if self.input.is_empty() {
21998            return None;
21999        }
22000
22001        let mut iter = self.input.graphemes(true).peekable();
22002        let mut offset = 0;
22003        let mut grapheme_len = 0;
22004        if let Some(first_grapheme) = iter.next() {
22005            let is_newline = first_grapheme == "\n";
22006            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22007            offset += first_grapheme.len();
22008            grapheme_len += 1;
22009            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22010                if let Some(grapheme) = iter.peek().copied()
22011                    && should_stay_with_preceding_ideograph(grapheme)
22012                {
22013                    offset += grapheme.len();
22014                    grapheme_len += 1;
22015                }
22016            } else {
22017                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22018                let mut next_word_bound = words.peek().copied();
22019                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22020                    next_word_bound = words.next();
22021                }
22022                while let Some(grapheme) = iter.peek().copied() {
22023                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22024                        break;
22025                    };
22026                    if is_grapheme_whitespace(grapheme) != is_whitespace
22027                        || (grapheme == "\n") != is_newline
22028                    {
22029                        break;
22030                    };
22031                    offset += grapheme.len();
22032                    grapheme_len += 1;
22033                    iter.next();
22034                }
22035            }
22036            let token = &self.input[..offset];
22037            self.input = &self.input[offset..];
22038            if token == "\n" {
22039                Some(WordBreakToken::Newline)
22040            } else if is_whitespace {
22041                Some(WordBreakToken::InlineWhitespace {
22042                    token,
22043                    grapheme_len,
22044                })
22045            } else {
22046                Some(WordBreakToken::Word {
22047                    token,
22048                    grapheme_len,
22049                })
22050            }
22051        } else {
22052            None
22053        }
22054    }
22055}
22056
22057#[test]
22058fn test_word_breaking_tokenizer() {
22059    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22060        ("", &[]),
22061        ("  ", &[whitespace("  ", 2)]),
22062        ("Ʒ", &[word("Ʒ", 1)]),
22063        ("Ǽ", &[word("Ǽ", 1)]),
22064        ("", &[word("", 1)]),
22065        ("⋑⋑", &[word("⋑⋑", 2)]),
22066        (
22067            "原理,进而",
22068            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22069        ),
22070        (
22071            "hello world",
22072            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22073        ),
22074        (
22075            "hello, world",
22076            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22077        ),
22078        (
22079            "  hello world",
22080            &[
22081                whitespace("  ", 2),
22082                word("hello", 5),
22083                whitespace(" ", 1),
22084                word("world", 5),
22085            ],
22086        ),
22087        (
22088            "这是什么 \n 钢笔",
22089            &[
22090                word("", 1),
22091                word("", 1),
22092                word("", 1),
22093                word("", 1),
22094                whitespace(" ", 1),
22095                newline(),
22096                whitespace(" ", 1),
22097                word("", 1),
22098                word("", 1),
22099            ],
22100        ),
22101        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22102    ];
22103
22104    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22105        WordBreakToken::Word {
22106            token,
22107            grapheme_len,
22108        }
22109    }
22110
22111    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22112        WordBreakToken::InlineWhitespace {
22113            token,
22114            grapheme_len,
22115        }
22116    }
22117
22118    fn newline() -> WordBreakToken<'static> {
22119        WordBreakToken::Newline
22120    }
22121
22122    for (input, result) in tests {
22123        assert_eq!(
22124            WordBreakingTokenizer::new(input)
22125                .collect::<Vec<_>>()
22126                .as_slice(),
22127            *result,
22128        );
22129    }
22130}
22131
22132fn wrap_with_prefix(
22133    first_line_prefix: String,
22134    subsequent_lines_prefix: String,
22135    unwrapped_text: String,
22136    wrap_column: usize,
22137    tab_size: NonZeroU32,
22138    preserve_existing_whitespace: bool,
22139) -> String {
22140    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22141    let subsequent_lines_prefix_len =
22142        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22143    let mut wrapped_text = String::new();
22144    let mut current_line = first_line_prefix;
22145    let mut is_first_line = true;
22146
22147    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22148    let mut current_line_len = first_line_prefix_len;
22149    let mut in_whitespace = false;
22150    for token in tokenizer {
22151        let have_preceding_whitespace = in_whitespace;
22152        match token {
22153            WordBreakToken::Word {
22154                token,
22155                grapheme_len,
22156            } => {
22157                in_whitespace = false;
22158                let current_prefix_len = if is_first_line {
22159                    first_line_prefix_len
22160                } else {
22161                    subsequent_lines_prefix_len
22162                };
22163                if current_line_len + grapheme_len > wrap_column
22164                    && current_line_len != current_prefix_len
22165                {
22166                    wrapped_text.push_str(current_line.trim_end());
22167                    wrapped_text.push('\n');
22168                    is_first_line = false;
22169                    current_line = subsequent_lines_prefix.clone();
22170                    current_line_len = subsequent_lines_prefix_len;
22171                }
22172                current_line.push_str(token);
22173                current_line_len += grapheme_len;
22174            }
22175            WordBreakToken::InlineWhitespace {
22176                mut token,
22177                mut grapheme_len,
22178            } => {
22179                in_whitespace = true;
22180                if have_preceding_whitespace && !preserve_existing_whitespace {
22181                    continue;
22182                }
22183                if !preserve_existing_whitespace {
22184                    token = " ";
22185                    grapheme_len = 1;
22186                }
22187                let current_prefix_len = if is_first_line {
22188                    first_line_prefix_len
22189                } else {
22190                    subsequent_lines_prefix_len
22191                };
22192                if current_line_len + grapheme_len > wrap_column {
22193                    wrapped_text.push_str(current_line.trim_end());
22194                    wrapped_text.push('\n');
22195                    is_first_line = false;
22196                    current_line = subsequent_lines_prefix.clone();
22197                    current_line_len = subsequent_lines_prefix_len;
22198                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22199                    current_line.push_str(token);
22200                    current_line_len += grapheme_len;
22201                }
22202            }
22203            WordBreakToken::Newline => {
22204                in_whitespace = true;
22205                let current_prefix_len = if is_first_line {
22206                    first_line_prefix_len
22207                } else {
22208                    subsequent_lines_prefix_len
22209                };
22210                if preserve_existing_whitespace {
22211                    wrapped_text.push_str(current_line.trim_end());
22212                    wrapped_text.push('\n');
22213                    is_first_line = false;
22214                    current_line = subsequent_lines_prefix.clone();
22215                    current_line_len = subsequent_lines_prefix_len;
22216                } else if have_preceding_whitespace {
22217                    continue;
22218                } else if current_line_len + 1 > wrap_column
22219                    && current_line_len != current_prefix_len
22220                {
22221                    wrapped_text.push_str(current_line.trim_end());
22222                    wrapped_text.push('\n');
22223                    is_first_line = false;
22224                    current_line = subsequent_lines_prefix.clone();
22225                    current_line_len = subsequent_lines_prefix_len;
22226                } else if current_line_len != current_prefix_len {
22227                    current_line.push(' ');
22228                    current_line_len += 1;
22229                }
22230            }
22231        }
22232    }
22233
22234    if !current_line.is_empty() {
22235        wrapped_text.push_str(&current_line);
22236    }
22237    wrapped_text
22238}
22239
22240#[test]
22241fn test_wrap_with_prefix() {
22242    assert_eq!(
22243        wrap_with_prefix(
22244            "# ".to_string(),
22245            "# ".to_string(),
22246            "abcdefg".to_string(),
22247            4,
22248            NonZeroU32::new(4).unwrap(),
22249            false,
22250        ),
22251        "# abcdefg"
22252    );
22253    assert_eq!(
22254        wrap_with_prefix(
22255            "".to_string(),
22256            "".to_string(),
22257            "\thello world".to_string(),
22258            8,
22259            NonZeroU32::new(4).unwrap(),
22260            false,
22261        ),
22262        "hello\nworld"
22263    );
22264    assert_eq!(
22265        wrap_with_prefix(
22266            "// ".to_string(),
22267            "// ".to_string(),
22268            "xx \nyy zz aa bb cc".to_string(),
22269            12,
22270            NonZeroU32::new(4).unwrap(),
22271            false,
22272        ),
22273        "// xx yy zz\n// aa bb cc"
22274    );
22275    assert_eq!(
22276        wrap_with_prefix(
22277            String::new(),
22278            String::new(),
22279            "这是什么 \n 钢笔".to_string(),
22280            3,
22281            NonZeroU32::new(4).unwrap(),
22282            false,
22283        ),
22284        "这是什\n么 钢\n"
22285    );
22286}
22287
22288pub trait CollaborationHub {
22289    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22290    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22291    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22292}
22293
22294impl CollaborationHub for Entity<Project> {
22295    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22296        self.read(cx).collaborators()
22297    }
22298
22299    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22300        self.read(cx).user_store().read(cx).participant_indices()
22301    }
22302
22303    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22304        let this = self.read(cx);
22305        let user_ids = this.collaborators().values().map(|c| c.user_id);
22306        this.user_store().read(cx).participant_names(user_ids, cx)
22307    }
22308}
22309
22310pub trait SemanticsProvider {
22311    fn hover(
22312        &self,
22313        buffer: &Entity<Buffer>,
22314        position: text::Anchor,
22315        cx: &mut App,
22316    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22317
22318    fn inline_values(
22319        &self,
22320        buffer_handle: Entity<Buffer>,
22321        range: Range<text::Anchor>,
22322        cx: &mut App,
22323    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22324
22325    fn inlay_hints(
22326        &self,
22327        buffer_handle: Entity<Buffer>,
22328        range: Range<text::Anchor>,
22329        cx: &mut App,
22330    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22331
22332    fn resolve_inlay_hint(
22333        &self,
22334        hint: InlayHint,
22335        buffer_handle: Entity<Buffer>,
22336        server_id: LanguageServerId,
22337        cx: &mut App,
22338    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22339
22340    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22341
22342    fn document_highlights(
22343        &self,
22344        buffer: &Entity<Buffer>,
22345        position: text::Anchor,
22346        cx: &mut App,
22347    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22348
22349    fn definitions(
22350        &self,
22351        buffer: &Entity<Buffer>,
22352        position: text::Anchor,
22353        kind: GotoDefinitionKind,
22354        cx: &mut App,
22355    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22356
22357    fn range_for_rename(
22358        &self,
22359        buffer: &Entity<Buffer>,
22360        position: text::Anchor,
22361        cx: &mut App,
22362    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22363
22364    fn perform_rename(
22365        &self,
22366        buffer: &Entity<Buffer>,
22367        position: text::Anchor,
22368        new_name: String,
22369        cx: &mut App,
22370    ) -> Option<Task<Result<ProjectTransaction>>>;
22371}
22372
22373pub trait CompletionProvider {
22374    fn completions(
22375        &self,
22376        excerpt_id: ExcerptId,
22377        buffer: &Entity<Buffer>,
22378        buffer_position: text::Anchor,
22379        trigger: CompletionContext,
22380        window: &mut Window,
22381        cx: &mut Context<Editor>,
22382    ) -> Task<Result<Vec<CompletionResponse>>>;
22383
22384    fn resolve_completions(
22385        &self,
22386        _buffer: Entity<Buffer>,
22387        _completion_indices: Vec<usize>,
22388        _completions: Rc<RefCell<Box<[Completion]>>>,
22389        _cx: &mut Context<Editor>,
22390    ) -> Task<Result<bool>> {
22391        Task::ready(Ok(false))
22392    }
22393
22394    fn apply_additional_edits_for_completion(
22395        &self,
22396        _buffer: Entity<Buffer>,
22397        _completions: Rc<RefCell<Box<[Completion]>>>,
22398        _completion_index: usize,
22399        _push_to_history: bool,
22400        _cx: &mut Context<Editor>,
22401    ) -> Task<Result<Option<language::Transaction>>> {
22402        Task::ready(Ok(None))
22403    }
22404
22405    fn is_completion_trigger(
22406        &self,
22407        buffer: &Entity<Buffer>,
22408        position: language::Anchor,
22409        text: &str,
22410        trigger_in_words: bool,
22411        menu_is_open: bool,
22412        cx: &mut Context<Editor>,
22413    ) -> bool;
22414
22415    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22416
22417    fn sort_completions(&self) -> bool {
22418        true
22419    }
22420
22421    fn filter_completions(&self) -> bool {
22422        true
22423    }
22424}
22425
22426pub trait CodeActionProvider {
22427    fn id(&self) -> Arc<str>;
22428
22429    fn code_actions(
22430        &self,
22431        buffer: &Entity<Buffer>,
22432        range: Range<text::Anchor>,
22433        window: &mut Window,
22434        cx: &mut App,
22435    ) -> Task<Result<Vec<CodeAction>>>;
22436
22437    fn apply_code_action(
22438        &self,
22439        buffer_handle: Entity<Buffer>,
22440        action: CodeAction,
22441        excerpt_id: ExcerptId,
22442        push_to_history: bool,
22443        window: &mut Window,
22444        cx: &mut App,
22445    ) -> Task<Result<ProjectTransaction>>;
22446}
22447
22448impl CodeActionProvider for Entity<Project> {
22449    fn id(&self) -> Arc<str> {
22450        "project".into()
22451    }
22452
22453    fn code_actions(
22454        &self,
22455        buffer: &Entity<Buffer>,
22456        range: Range<text::Anchor>,
22457        _window: &mut Window,
22458        cx: &mut App,
22459    ) -> Task<Result<Vec<CodeAction>>> {
22460        self.update(cx, |project, cx| {
22461            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22462            let code_actions = project.code_actions(buffer, range, None, cx);
22463            cx.background_spawn(async move {
22464                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22465                Ok(code_lens_actions
22466                    .context("code lens fetch")?
22467                    .into_iter()
22468                    .flatten()
22469                    .chain(
22470                        code_actions
22471                            .context("code action fetch")?
22472                            .into_iter()
22473                            .flatten(),
22474                    )
22475                    .collect())
22476            })
22477        })
22478    }
22479
22480    fn apply_code_action(
22481        &self,
22482        buffer_handle: Entity<Buffer>,
22483        action: CodeAction,
22484        _excerpt_id: ExcerptId,
22485        push_to_history: bool,
22486        _window: &mut Window,
22487        cx: &mut App,
22488    ) -> Task<Result<ProjectTransaction>> {
22489        self.update(cx, |project, cx| {
22490            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22491        })
22492    }
22493}
22494
22495fn snippet_completions(
22496    project: &Project,
22497    buffer: &Entity<Buffer>,
22498    buffer_position: text::Anchor,
22499    cx: &mut App,
22500) -> Task<Result<CompletionResponse>> {
22501    let languages = buffer.read(cx).languages_at(buffer_position);
22502    let snippet_store = project.snippets().read(cx);
22503
22504    let scopes: Vec<_> = languages
22505        .iter()
22506        .filter_map(|language| {
22507            let language_name = language.lsp_id();
22508            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22509
22510            if snippets.is_empty() {
22511                None
22512            } else {
22513                Some((language.default_scope(), snippets))
22514            }
22515        })
22516        .collect();
22517
22518    if scopes.is_empty() {
22519        return Task::ready(Ok(CompletionResponse {
22520            completions: vec![],
22521            display_options: CompletionDisplayOptions::default(),
22522            is_incomplete: false,
22523        }));
22524    }
22525
22526    let snapshot = buffer.read(cx).text_snapshot();
22527    let chars: String = snapshot
22528        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22529        .collect();
22530    let executor = cx.background_executor().clone();
22531
22532    cx.background_spawn(async move {
22533        let mut is_incomplete = false;
22534        let mut completions: Vec<Completion> = Vec::new();
22535        for (scope, snippets) in scopes.into_iter() {
22536            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22537            let mut last_word = chars
22538                .chars()
22539                .take_while(|c| classifier.is_word(*c))
22540                .collect::<String>();
22541            last_word = last_word.chars().rev().collect();
22542
22543            if last_word.is_empty() {
22544                return Ok(CompletionResponse {
22545                    completions: vec![],
22546                    display_options: CompletionDisplayOptions::default(),
22547                    is_incomplete: true,
22548                });
22549            }
22550
22551            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22552            let to_lsp = |point: &text::Anchor| {
22553                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22554                point_to_lsp(end)
22555            };
22556            let lsp_end = to_lsp(&buffer_position);
22557
22558            let candidates = snippets
22559                .iter()
22560                .enumerate()
22561                .flat_map(|(ix, snippet)| {
22562                    snippet
22563                        .prefix
22564                        .iter()
22565                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22566                })
22567                .collect::<Vec<StringMatchCandidate>>();
22568
22569            const MAX_RESULTS: usize = 100;
22570            let mut matches = fuzzy::match_strings(
22571                &candidates,
22572                &last_word,
22573                last_word.chars().any(|c| c.is_uppercase()),
22574                true,
22575                MAX_RESULTS,
22576                &Default::default(),
22577                executor.clone(),
22578            )
22579            .await;
22580
22581            if matches.len() >= MAX_RESULTS {
22582                is_incomplete = true;
22583            }
22584
22585            // Remove all candidates where the query's start does not match the start of any word in the candidate
22586            if let Some(query_start) = last_word.chars().next() {
22587                matches.retain(|string_match| {
22588                    split_words(&string_match.string).any(|word| {
22589                        // Check that the first codepoint of the word as lowercase matches the first
22590                        // codepoint of the query as lowercase
22591                        word.chars()
22592                            .flat_map(|codepoint| codepoint.to_lowercase())
22593                            .zip(query_start.to_lowercase())
22594                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22595                    })
22596                });
22597            }
22598
22599            let matched_strings = matches
22600                .into_iter()
22601                .map(|m| m.string)
22602                .collect::<HashSet<_>>();
22603
22604            completions.extend(snippets.iter().filter_map(|snippet| {
22605                let matching_prefix = snippet
22606                    .prefix
22607                    .iter()
22608                    .find(|prefix| matched_strings.contains(*prefix))?;
22609                let start = as_offset - last_word.len();
22610                let start = snapshot.anchor_before(start);
22611                let range = start..buffer_position;
22612                let lsp_start = to_lsp(&start);
22613                let lsp_range = lsp::Range {
22614                    start: lsp_start,
22615                    end: lsp_end,
22616                };
22617                Some(Completion {
22618                    replace_range: range,
22619                    new_text: snippet.body.clone(),
22620                    source: CompletionSource::Lsp {
22621                        insert_range: None,
22622                        server_id: LanguageServerId(usize::MAX),
22623                        resolved: true,
22624                        lsp_completion: Box::new(lsp::CompletionItem {
22625                            label: snippet.prefix.first().unwrap().clone(),
22626                            kind: Some(CompletionItemKind::SNIPPET),
22627                            label_details: snippet.description.as_ref().map(|description| {
22628                                lsp::CompletionItemLabelDetails {
22629                                    detail: Some(description.clone()),
22630                                    description: None,
22631                                }
22632                            }),
22633                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22634                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22635                                lsp::InsertReplaceEdit {
22636                                    new_text: snippet.body.clone(),
22637                                    insert: lsp_range,
22638                                    replace: lsp_range,
22639                                },
22640                            )),
22641                            filter_text: Some(snippet.body.clone()),
22642                            sort_text: Some(char::MAX.to_string()),
22643                            ..lsp::CompletionItem::default()
22644                        }),
22645                        lsp_defaults: None,
22646                    },
22647                    label: CodeLabel {
22648                        text: matching_prefix.clone(),
22649                        runs: Vec::new(),
22650                        filter_range: 0..matching_prefix.len(),
22651                    },
22652                    icon_path: None,
22653                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22654                        single_line: snippet.name.clone().into(),
22655                        plain_text: snippet
22656                            .description
22657                            .clone()
22658                            .map(|description| description.into()),
22659                    }),
22660                    insert_text_mode: None,
22661                    confirm: None,
22662                })
22663            }))
22664        }
22665
22666        Ok(CompletionResponse {
22667            completions,
22668            display_options: CompletionDisplayOptions::default(),
22669            is_incomplete,
22670        })
22671    })
22672}
22673
22674impl CompletionProvider for Entity<Project> {
22675    fn completions(
22676        &self,
22677        _excerpt_id: ExcerptId,
22678        buffer: &Entity<Buffer>,
22679        buffer_position: text::Anchor,
22680        options: CompletionContext,
22681        _window: &mut Window,
22682        cx: &mut Context<Editor>,
22683    ) -> Task<Result<Vec<CompletionResponse>>> {
22684        self.update(cx, |project, cx| {
22685            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22686            let project_completions = project.completions(buffer, buffer_position, options, cx);
22687            cx.background_spawn(async move {
22688                let mut responses = project_completions.await?;
22689                let snippets = snippets.await?;
22690                if !snippets.completions.is_empty() {
22691                    responses.push(snippets);
22692                }
22693                Ok(responses)
22694            })
22695        })
22696    }
22697
22698    fn resolve_completions(
22699        &self,
22700        buffer: Entity<Buffer>,
22701        completion_indices: Vec<usize>,
22702        completions: Rc<RefCell<Box<[Completion]>>>,
22703        cx: &mut Context<Editor>,
22704    ) -> Task<Result<bool>> {
22705        self.update(cx, |project, cx| {
22706            project.lsp_store().update(cx, |lsp_store, cx| {
22707                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22708            })
22709        })
22710    }
22711
22712    fn apply_additional_edits_for_completion(
22713        &self,
22714        buffer: Entity<Buffer>,
22715        completions: Rc<RefCell<Box<[Completion]>>>,
22716        completion_index: usize,
22717        push_to_history: bool,
22718        cx: &mut Context<Editor>,
22719    ) -> Task<Result<Option<language::Transaction>>> {
22720        self.update(cx, |project, cx| {
22721            project.lsp_store().update(cx, |lsp_store, cx| {
22722                lsp_store.apply_additional_edits_for_completion(
22723                    buffer,
22724                    completions,
22725                    completion_index,
22726                    push_to_history,
22727                    cx,
22728                )
22729            })
22730        })
22731    }
22732
22733    fn is_completion_trigger(
22734        &self,
22735        buffer: &Entity<Buffer>,
22736        position: language::Anchor,
22737        text: &str,
22738        trigger_in_words: bool,
22739        menu_is_open: bool,
22740        cx: &mut Context<Editor>,
22741    ) -> bool {
22742        let mut chars = text.chars();
22743        let char = if let Some(char) = chars.next() {
22744            char
22745        } else {
22746            return false;
22747        };
22748        if chars.next().is_some() {
22749            return false;
22750        }
22751
22752        let buffer = buffer.read(cx);
22753        let snapshot = buffer.snapshot();
22754        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22755            return false;
22756        }
22757        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22758        if trigger_in_words && classifier.is_word(char) {
22759            return true;
22760        }
22761
22762        buffer.completion_triggers().contains(text)
22763    }
22764}
22765
22766impl SemanticsProvider for Entity<Project> {
22767    fn hover(
22768        &self,
22769        buffer: &Entity<Buffer>,
22770        position: text::Anchor,
22771        cx: &mut App,
22772    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22773        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22774    }
22775
22776    fn document_highlights(
22777        &self,
22778        buffer: &Entity<Buffer>,
22779        position: text::Anchor,
22780        cx: &mut App,
22781    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22782        Some(self.update(cx, |project, cx| {
22783            project.document_highlights(buffer, position, cx)
22784        }))
22785    }
22786
22787    fn definitions(
22788        &self,
22789        buffer: &Entity<Buffer>,
22790        position: text::Anchor,
22791        kind: GotoDefinitionKind,
22792        cx: &mut App,
22793    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22794        Some(self.update(cx, |project, cx| match kind {
22795            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22796            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22797            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22798            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22799        }))
22800    }
22801
22802    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22803        self.update(cx, |project, cx| {
22804            if project
22805                .active_debug_session(cx)
22806                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22807            {
22808                return true;
22809            }
22810
22811            buffer.update(cx, |buffer, cx| {
22812                project.any_language_server_supports_inlay_hints(buffer, cx)
22813            })
22814        })
22815    }
22816
22817    fn inline_values(
22818        &self,
22819        buffer_handle: Entity<Buffer>,
22820        range: Range<text::Anchor>,
22821        cx: &mut App,
22822    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22823        self.update(cx, |project, cx| {
22824            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22825
22826            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22827        })
22828    }
22829
22830    fn inlay_hints(
22831        &self,
22832        buffer_handle: Entity<Buffer>,
22833        range: Range<text::Anchor>,
22834        cx: &mut App,
22835    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22836        Some(self.update(cx, |project, cx| {
22837            project.inlay_hints(buffer_handle, range, cx)
22838        }))
22839    }
22840
22841    fn resolve_inlay_hint(
22842        &self,
22843        hint: InlayHint,
22844        buffer_handle: Entity<Buffer>,
22845        server_id: LanguageServerId,
22846        cx: &mut App,
22847    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22848        Some(self.update(cx, |project, cx| {
22849            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22850        }))
22851    }
22852
22853    fn range_for_rename(
22854        &self,
22855        buffer: &Entity<Buffer>,
22856        position: text::Anchor,
22857        cx: &mut App,
22858    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22859        Some(self.update(cx, |project, cx| {
22860            let buffer = buffer.clone();
22861            let task = project.prepare_rename(buffer.clone(), position, cx);
22862            cx.spawn(async move |_, cx| {
22863                Ok(match task.await? {
22864                    PrepareRenameResponse::Success(range) => Some(range),
22865                    PrepareRenameResponse::InvalidPosition => None,
22866                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22867                        // Fallback on using TreeSitter info to determine identifier range
22868                        buffer.read_with(cx, |buffer, _| {
22869                            let snapshot = buffer.snapshot();
22870                            let (range, kind) = snapshot.surrounding_word(position, false);
22871                            if kind != Some(CharKind::Word) {
22872                                return None;
22873                            }
22874                            Some(
22875                                snapshot.anchor_before(range.start)
22876                                    ..snapshot.anchor_after(range.end),
22877                            )
22878                        })?
22879                    }
22880                })
22881            })
22882        }))
22883    }
22884
22885    fn perform_rename(
22886        &self,
22887        buffer: &Entity<Buffer>,
22888        position: text::Anchor,
22889        new_name: String,
22890        cx: &mut App,
22891    ) -> Option<Task<Result<ProjectTransaction>>> {
22892        Some(self.update(cx, |project, cx| {
22893            project.perform_rename(buffer.clone(), position, new_name, cx)
22894        }))
22895    }
22896}
22897
22898fn inlay_hint_settings(
22899    location: Anchor,
22900    snapshot: &MultiBufferSnapshot,
22901    cx: &mut Context<Editor>,
22902) -> InlayHintSettings {
22903    let file = snapshot.file_at(location);
22904    let language = snapshot.language_at(location).map(|l| l.name());
22905    language_settings(language, file, cx).inlay_hints
22906}
22907
22908fn consume_contiguous_rows(
22909    contiguous_row_selections: &mut Vec<Selection<Point>>,
22910    selection: &Selection<Point>,
22911    display_map: &DisplaySnapshot,
22912    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22913) -> (MultiBufferRow, MultiBufferRow) {
22914    contiguous_row_selections.push(selection.clone());
22915    let start_row = starting_row(selection, display_map);
22916    let mut end_row = ending_row(selection, display_map);
22917
22918    while let Some(next_selection) = selections.peek() {
22919        if next_selection.start.row <= end_row.0 {
22920            end_row = ending_row(next_selection, display_map);
22921            contiguous_row_selections.push(selections.next().unwrap().clone());
22922        } else {
22923            break;
22924        }
22925    }
22926    (start_row, end_row)
22927}
22928
22929fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22930    if selection.start.column > 0 {
22931        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22932    } else {
22933        MultiBufferRow(selection.start.row)
22934    }
22935}
22936
22937fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22938    if next_selection.end.column > 0 || next_selection.is_empty() {
22939        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22940    } else {
22941        MultiBufferRow(next_selection.end.row)
22942    }
22943}
22944
22945impl EditorSnapshot {
22946    pub fn remote_selections_in_range<'a>(
22947        &'a self,
22948        range: &'a Range<Anchor>,
22949        collaboration_hub: &dyn CollaborationHub,
22950        cx: &'a App,
22951    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22952        let participant_names = collaboration_hub.user_names(cx);
22953        let participant_indices = collaboration_hub.user_participant_indices(cx);
22954        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22955        let collaborators_by_replica_id = collaborators_by_peer_id
22956            .values()
22957            .map(|collaborator| (collaborator.replica_id, collaborator))
22958            .collect::<HashMap<_, _>>();
22959        self.buffer_snapshot
22960            .selections_in_range(range, false)
22961            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22962                if replica_id == AGENT_REPLICA_ID {
22963                    Some(RemoteSelection {
22964                        replica_id,
22965                        selection,
22966                        cursor_shape,
22967                        line_mode,
22968                        collaborator_id: CollaboratorId::Agent,
22969                        user_name: Some("Agent".into()),
22970                        color: cx.theme().players().agent(),
22971                    })
22972                } else {
22973                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22974                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22975                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22976                    Some(RemoteSelection {
22977                        replica_id,
22978                        selection,
22979                        cursor_shape,
22980                        line_mode,
22981                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22982                        user_name,
22983                        color: if let Some(index) = participant_index {
22984                            cx.theme().players().color_for_participant(index.0)
22985                        } else {
22986                            cx.theme().players().absent()
22987                        },
22988                    })
22989                }
22990            })
22991    }
22992
22993    pub fn hunks_for_ranges(
22994        &self,
22995        ranges: impl IntoIterator<Item = Range<Point>>,
22996    ) -> Vec<MultiBufferDiffHunk> {
22997        let mut hunks = Vec::new();
22998        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22999            HashMap::default();
23000        for query_range in ranges {
23001            let query_rows =
23002                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23003            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23004                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23005            ) {
23006                // Include deleted hunks that are adjacent to the query range, because
23007                // otherwise they would be missed.
23008                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23009                if hunk.status().is_deleted() {
23010                    intersects_range |= hunk.row_range.start == query_rows.end;
23011                    intersects_range |= hunk.row_range.end == query_rows.start;
23012                }
23013                if intersects_range {
23014                    if !processed_buffer_rows
23015                        .entry(hunk.buffer_id)
23016                        .or_default()
23017                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23018                    {
23019                        continue;
23020                    }
23021                    hunks.push(hunk);
23022                }
23023            }
23024        }
23025
23026        hunks
23027    }
23028
23029    fn display_diff_hunks_for_rows<'a>(
23030        &'a self,
23031        display_rows: Range<DisplayRow>,
23032        folded_buffers: &'a HashSet<BufferId>,
23033    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23034        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23035        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23036
23037        self.buffer_snapshot
23038            .diff_hunks_in_range(buffer_start..buffer_end)
23039            .filter_map(|hunk| {
23040                if folded_buffers.contains(&hunk.buffer_id) {
23041                    return None;
23042                }
23043
23044                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23045                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23046
23047                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23048                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23049
23050                let display_hunk = if hunk_display_start.column() != 0 {
23051                    DisplayDiffHunk::Folded {
23052                        display_row: hunk_display_start.row(),
23053                    }
23054                } else {
23055                    let mut end_row = hunk_display_end.row();
23056                    if hunk_display_end.column() > 0 {
23057                        end_row.0 += 1;
23058                    }
23059                    let is_created_file = hunk.is_created_file();
23060                    DisplayDiffHunk::Unfolded {
23061                        status: hunk.status(),
23062                        diff_base_byte_range: hunk.diff_base_byte_range,
23063                        display_row_range: hunk_display_start.row()..end_row,
23064                        multi_buffer_range: Anchor::range_in_buffer(
23065                            hunk.excerpt_id,
23066                            hunk.buffer_id,
23067                            hunk.buffer_range,
23068                        ),
23069                        is_created_file,
23070                    }
23071                };
23072
23073                Some(display_hunk)
23074            })
23075    }
23076
23077    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23078        self.display_snapshot.buffer_snapshot.language_at(position)
23079    }
23080
23081    pub fn is_focused(&self) -> bool {
23082        self.is_focused
23083    }
23084
23085    pub fn placeholder_text(&self) -> Option<String> {
23086        self.placeholder_display_snapshot
23087            .as_ref()
23088            .map(|display_map| display_map.text())
23089    }
23090
23091    pub fn scroll_position(&self) -> gpui::Point<f32> {
23092        self.scroll_anchor.scroll_position(&self.display_snapshot)
23093    }
23094
23095    fn gutter_dimensions(
23096        &self,
23097        font_id: FontId,
23098        font_size: Pixels,
23099        max_line_number_width: Pixels,
23100        cx: &App,
23101    ) -> Option<GutterDimensions> {
23102        if !self.show_gutter {
23103            return None;
23104        }
23105
23106        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23107        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23108
23109        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23110            matches!(
23111                ProjectSettings::get_global(cx).git.git_gutter,
23112                Some(GitGutterSetting::TrackedFiles)
23113            )
23114        });
23115        let gutter_settings = EditorSettings::get_global(cx).gutter;
23116        let show_line_numbers = self
23117            .show_line_numbers
23118            .unwrap_or(gutter_settings.line_numbers);
23119        let line_gutter_width = if show_line_numbers {
23120            // Avoid flicker-like gutter resizes when the line number gains another digit by
23121            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23122            let min_width_for_number_on_gutter =
23123                ch_advance * gutter_settings.min_line_number_digits as f32;
23124            max_line_number_width.max(min_width_for_number_on_gutter)
23125        } else {
23126            0.0.into()
23127        };
23128
23129        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23130        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23131
23132        let git_blame_entries_width =
23133            self.git_blame_gutter_max_author_length
23134                .map(|max_author_length| {
23135                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23136                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23137
23138                    /// The number of characters to dedicate to gaps and margins.
23139                    const SPACING_WIDTH: usize = 4;
23140
23141                    let max_char_count = max_author_length.min(renderer.max_author_length())
23142                        + ::git::SHORT_SHA_LENGTH
23143                        + MAX_RELATIVE_TIMESTAMP.len()
23144                        + SPACING_WIDTH;
23145
23146                    ch_advance * max_char_count
23147                });
23148
23149        let is_singleton = self.buffer_snapshot.is_singleton();
23150
23151        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23152        left_padding += if !is_singleton {
23153            ch_width * 4.0
23154        } else if show_runnables || show_breakpoints {
23155            ch_width * 3.0
23156        } else if show_git_gutter && show_line_numbers {
23157            ch_width * 2.0
23158        } else if show_git_gutter || show_line_numbers {
23159            ch_width
23160        } else {
23161            px(0.)
23162        };
23163
23164        let shows_folds = is_singleton && gutter_settings.folds;
23165
23166        let right_padding = if shows_folds && show_line_numbers {
23167            ch_width * 4.0
23168        } else if shows_folds || (!is_singleton && show_line_numbers) {
23169            ch_width * 3.0
23170        } else if show_line_numbers {
23171            ch_width
23172        } else {
23173            px(0.)
23174        };
23175
23176        Some(GutterDimensions {
23177            left_padding,
23178            right_padding,
23179            width: line_gutter_width + left_padding + right_padding,
23180            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23181            git_blame_entries_width,
23182        })
23183    }
23184
23185    pub fn render_crease_toggle(
23186        &self,
23187        buffer_row: MultiBufferRow,
23188        row_contains_cursor: bool,
23189        editor: Entity<Editor>,
23190        window: &mut Window,
23191        cx: &mut App,
23192    ) -> Option<AnyElement> {
23193        let folded = self.is_line_folded(buffer_row);
23194        let mut is_foldable = false;
23195
23196        if let Some(crease) = self
23197            .crease_snapshot
23198            .query_row(buffer_row, &self.buffer_snapshot)
23199        {
23200            is_foldable = true;
23201            match crease {
23202                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23203                    if let Some(render_toggle) = render_toggle {
23204                        let toggle_callback =
23205                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23206                                if folded {
23207                                    editor.update(cx, |editor, cx| {
23208                                        editor.fold_at(buffer_row, window, cx)
23209                                    });
23210                                } else {
23211                                    editor.update(cx, |editor, cx| {
23212                                        editor.unfold_at(buffer_row, window, cx)
23213                                    });
23214                                }
23215                            });
23216                        return Some((render_toggle)(
23217                            buffer_row,
23218                            folded,
23219                            toggle_callback,
23220                            window,
23221                            cx,
23222                        ));
23223                    }
23224                }
23225            }
23226        }
23227
23228        is_foldable |= self.starts_indent(buffer_row);
23229
23230        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23231            Some(
23232                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23233                    .toggle_state(folded)
23234                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23235                        if folded {
23236                            this.unfold_at(buffer_row, window, cx);
23237                        } else {
23238                            this.fold_at(buffer_row, window, cx);
23239                        }
23240                    }))
23241                    .into_any_element(),
23242            )
23243        } else {
23244            None
23245        }
23246    }
23247
23248    pub fn render_crease_trailer(
23249        &self,
23250        buffer_row: MultiBufferRow,
23251        window: &mut Window,
23252        cx: &mut App,
23253    ) -> Option<AnyElement> {
23254        let folded = self.is_line_folded(buffer_row);
23255        if let Crease::Inline { render_trailer, .. } = self
23256            .crease_snapshot
23257            .query_row(buffer_row, &self.buffer_snapshot)?
23258        {
23259            let render_trailer = render_trailer.as_ref()?;
23260            Some(render_trailer(buffer_row, folded, window, cx))
23261        } else {
23262            None
23263        }
23264    }
23265}
23266
23267impl Deref for EditorSnapshot {
23268    type Target = DisplaySnapshot;
23269
23270    fn deref(&self) -> &Self::Target {
23271        &self.display_snapshot
23272    }
23273}
23274
23275#[derive(Clone, Debug, PartialEq, Eq)]
23276pub enum EditorEvent {
23277    InputIgnored {
23278        text: Arc<str>,
23279    },
23280    InputHandled {
23281        utf16_range_to_replace: Option<Range<isize>>,
23282        text: Arc<str>,
23283    },
23284    ExcerptsAdded {
23285        buffer: Entity<Buffer>,
23286        predecessor: ExcerptId,
23287        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23288    },
23289    ExcerptsRemoved {
23290        ids: Vec<ExcerptId>,
23291        removed_buffer_ids: Vec<BufferId>,
23292    },
23293    BufferFoldToggled {
23294        ids: Vec<ExcerptId>,
23295        folded: bool,
23296    },
23297    ExcerptsEdited {
23298        ids: Vec<ExcerptId>,
23299    },
23300    ExcerptsExpanded {
23301        ids: Vec<ExcerptId>,
23302    },
23303    BufferEdited,
23304    Edited {
23305        transaction_id: clock::Lamport,
23306    },
23307    Reparsed(BufferId),
23308    Focused,
23309    FocusedIn,
23310    Blurred,
23311    DirtyChanged,
23312    Saved,
23313    TitleChanged,
23314    SelectionsChanged {
23315        local: bool,
23316    },
23317    ScrollPositionChanged {
23318        local: bool,
23319        autoscroll: bool,
23320    },
23321    TransactionUndone {
23322        transaction_id: clock::Lamport,
23323    },
23324    TransactionBegun {
23325        transaction_id: clock::Lamport,
23326    },
23327    CursorShapeChanged,
23328    BreadcrumbsChanged,
23329    PushedToNavHistory {
23330        anchor: Anchor,
23331        is_deactivate: bool,
23332    },
23333}
23334
23335impl EventEmitter<EditorEvent> for Editor {}
23336
23337impl Focusable for Editor {
23338    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23339        self.focus_handle.clone()
23340    }
23341}
23342
23343impl Render for Editor {
23344    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23345        let settings = ThemeSettings::get_global(cx);
23346
23347        let mut text_style = match self.mode {
23348            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23349                color: cx.theme().colors().editor_foreground,
23350                font_family: settings.ui_font.family.clone(),
23351                font_features: settings.ui_font.features.clone(),
23352                font_fallbacks: settings.ui_font.fallbacks.clone(),
23353                font_size: rems(0.875).into(),
23354                font_weight: settings.ui_font.weight,
23355                line_height: relative(settings.buffer_line_height.value()),
23356                ..Default::default()
23357            },
23358            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23359                color: cx.theme().colors().editor_foreground,
23360                font_family: settings.buffer_font.family.clone(),
23361                font_features: settings.buffer_font.features.clone(),
23362                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23363                font_size: settings.buffer_font_size(cx).into(),
23364                font_weight: settings.buffer_font.weight,
23365                line_height: relative(settings.buffer_line_height.value()),
23366                ..Default::default()
23367            },
23368        };
23369        if let Some(text_style_refinement) = &self.text_style_refinement {
23370            text_style.refine(text_style_refinement)
23371        }
23372
23373        let background = match self.mode {
23374            EditorMode::SingleLine => cx.theme().system().transparent,
23375            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23376            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23377            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23378        };
23379
23380        EditorElement::new(
23381            &cx.entity(),
23382            EditorStyle {
23383                background,
23384                border: cx.theme().colors().border,
23385                local_player: cx.theme().players().local(),
23386                text: text_style,
23387                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23388                syntax: cx.theme().syntax().clone(),
23389                status: cx.theme().status().clone(),
23390                inlay_hints_style: make_inlay_hints_style(cx),
23391                edit_prediction_styles: make_suggestion_styles(cx),
23392                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23393                show_underlines: self.diagnostics_enabled(),
23394            },
23395        )
23396    }
23397}
23398
23399impl EntityInputHandler for Editor {
23400    fn text_for_range(
23401        &mut self,
23402        range_utf16: Range<usize>,
23403        adjusted_range: &mut Option<Range<usize>>,
23404        _: &mut Window,
23405        cx: &mut Context<Self>,
23406    ) -> Option<String> {
23407        let snapshot = self.buffer.read(cx).read(cx);
23408        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23409        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23410        if (start.0..end.0) != range_utf16 {
23411            adjusted_range.replace(start.0..end.0);
23412        }
23413        Some(snapshot.text_for_range(start..end).collect())
23414    }
23415
23416    fn selected_text_range(
23417        &mut self,
23418        ignore_disabled_input: bool,
23419        _: &mut Window,
23420        cx: &mut Context<Self>,
23421    ) -> Option<UTF16Selection> {
23422        // Prevent the IME menu from appearing when holding down an alphabetic key
23423        // while input is disabled.
23424        if !ignore_disabled_input && !self.input_enabled {
23425            return None;
23426        }
23427
23428        let selection = self.selections.newest::<OffsetUtf16>(cx);
23429        let range = selection.range();
23430
23431        Some(UTF16Selection {
23432            range: range.start.0..range.end.0,
23433            reversed: selection.reversed,
23434        })
23435    }
23436
23437    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23438        let snapshot = self.buffer.read(cx).read(cx);
23439        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23440        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23441    }
23442
23443    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23444        self.clear_highlights::<InputComposition>(cx);
23445        self.ime_transaction.take();
23446    }
23447
23448    fn replace_text_in_range(
23449        &mut self,
23450        range_utf16: Option<Range<usize>>,
23451        text: &str,
23452        window: &mut Window,
23453        cx: &mut Context<Self>,
23454    ) {
23455        if !self.input_enabled {
23456            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23457            return;
23458        }
23459
23460        self.transact(window, cx, |this, window, cx| {
23461            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23462                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23463                Some(this.selection_replacement_ranges(range_utf16, cx))
23464            } else {
23465                this.marked_text_ranges(cx)
23466            };
23467
23468            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23469                let newest_selection_id = this.selections.newest_anchor().id;
23470                this.selections
23471                    .all::<OffsetUtf16>(cx)
23472                    .iter()
23473                    .zip(ranges_to_replace.iter())
23474                    .find_map(|(selection, range)| {
23475                        if selection.id == newest_selection_id {
23476                            Some(
23477                                (range.start.0 as isize - selection.head().0 as isize)
23478                                    ..(range.end.0 as isize - selection.head().0 as isize),
23479                            )
23480                        } else {
23481                            None
23482                        }
23483                    })
23484            });
23485
23486            cx.emit(EditorEvent::InputHandled {
23487                utf16_range_to_replace: range_to_replace,
23488                text: text.into(),
23489            });
23490
23491            if let Some(new_selected_ranges) = new_selected_ranges {
23492                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23493                    selections.select_ranges(new_selected_ranges)
23494                });
23495                this.backspace(&Default::default(), window, cx);
23496            }
23497
23498            this.handle_input(text, window, cx);
23499        });
23500
23501        if let Some(transaction) = self.ime_transaction {
23502            self.buffer.update(cx, |buffer, cx| {
23503                buffer.group_until_transaction(transaction, cx);
23504            });
23505        }
23506
23507        self.unmark_text(window, cx);
23508    }
23509
23510    fn replace_and_mark_text_in_range(
23511        &mut self,
23512        range_utf16: Option<Range<usize>>,
23513        text: &str,
23514        new_selected_range_utf16: Option<Range<usize>>,
23515        window: &mut Window,
23516        cx: &mut Context<Self>,
23517    ) {
23518        if !self.input_enabled {
23519            return;
23520        }
23521
23522        let transaction = self.transact(window, cx, |this, window, cx| {
23523            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23524                let snapshot = this.buffer.read(cx).read(cx);
23525                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23526                    for marked_range in &mut marked_ranges {
23527                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23528                        marked_range.start.0 += relative_range_utf16.start;
23529                        marked_range.start =
23530                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23531                        marked_range.end =
23532                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23533                    }
23534                }
23535                Some(marked_ranges)
23536            } else if let Some(range_utf16) = range_utf16 {
23537                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23538                Some(this.selection_replacement_ranges(range_utf16, cx))
23539            } else {
23540                None
23541            };
23542
23543            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23544                let newest_selection_id = this.selections.newest_anchor().id;
23545                this.selections
23546                    .all::<OffsetUtf16>(cx)
23547                    .iter()
23548                    .zip(ranges_to_replace.iter())
23549                    .find_map(|(selection, range)| {
23550                        if selection.id == newest_selection_id {
23551                            Some(
23552                                (range.start.0 as isize - selection.head().0 as isize)
23553                                    ..(range.end.0 as isize - selection.head().0 as isize),
23554                            )
23555                        } else {
23556                            None
23557                        }
23558                    })
23559            });
23560
23561            cx.emit(EditorEvent::InputHandled {
23562                utf16_range_to_replace: range_to_replace,
23563                text: text.into(),
23564            });
23565
23566            if let Some(ranges) = ranges_to_replace {
23567                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23568                    s.select_ranges(ranges)
23569                });
23570            }
23571
23572            let marked_ranges = {
23573                let snapshot = this.buffer.read(cx).read(cx);
23574                this.selections
23575                    .disjoint_anchors()
23576                    .iter()
23577                    .map(|selection| {
23578                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23579                    })
23580                    .collect::<Vec<_>>()
23581            };
23582
23583            if text.is_empty() {
23584                this.unmark_text(window, cx);
23585            } else {
23586                this.highlight_text::<InputComposition>(
23587                    marked_ranges.clone(),
23588                    HighlightStyle {
23589                        underline: Some(UnderlineStyle {
23590                            thickness: px(1.),
23591                            color: None,
23592                            wavy: false,
23593                        }),
23594                        ..Default::default()
23595                    },
23596                    cx,
23597                );
23598            }
23599
23600            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23601            let use_autoclose = this.use_autoclose;
23602            let use_auto_surround = this.use_auto_surround;
23603            this.set_use_autoclose(false);
23604            this.set_use_auto_surround(false);
23605            this.handle_input(text, window, cx);
23606            this.set_use_autoclose(use_autoclose);
23607            this.set_use_auto_surround(use_auto_surround);
23608
23609            if let Some(new_selected_range) = new_selected_range_utf16 {
23610                let snapshot = this.buffer.read(cx).read(cx);
23611                let new_selected_ranges = marked_ranges
23612                    .into_iter()
23613                    .map(|marked_range| {
23614                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23615                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23616                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23617                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23618                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23619                    })
23620                    .collect::<Vec<_>>();
23621
23622                drop(snapshot);
23623                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23624                    selections.select_ranges(new_selected_ranges)
23625                });
23626            }
23627        });
23628
23629        self.ime_transaction = self.ime_transaction.or(transaction);
23630        if let Some(transaction) = self.ime_transaction {
23631            self.buffer.update(cx, |buffer, cx| {
23632                buffer.group_until_transaction(transaction, cx);
23633            });
23634        }
23635
23636        if self.text_highlights::<InputComposition>(cx).is_none() {
23637            self.ime_transaction.take();
23638        }
23639    }
23640
23641    fn bounds_for_range(
23642        &mut self,
23643        range_utf16: Range<usize>,
23644        element_bounds: gpui::Bounds<Pixels>,
23645        window: &mut Window,
23646        cx: &mut Context<Self>,
23647    ) -> Option<gpui::Bounds<Pixels>> {
23648        let text_layout_details = self.text_layout_details(window);
23649        let CharacterDimensions {
23650            em_width,
23651            em_advance,
23652            line_height,
23653        } = self.character_dimensions(window);
23654
23655        let snapshot = self.snapshot(window, cx);
23656        let scroll_position = snapshot.scroll_position();
23657        let scroll_left = scroll_position.x * em_advance;
23658
23659        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23660        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23661            + self.gutter_dimensions.full_width();
23662        let y = line_height * (start.row().as_f32() - scroll_position.y);
23663
23664        Some(Bounds {
23665            origin: element_bounds.origin + point(x, y),
23666            size: size(em_width, line_height),
23667        })
23668    }
23669
23670    fn character_index_for_point(
23671        &mut self,
23672        point: gpui::Point<Pixels>,
23673        _window: &mut Window,
23674        _cx: &mut Context<Self>,
23675    ) -> Option<usize> {
23676        let position_map = self.last_position_map.as_ref()?;
23677        if !position_map.text_hitbox.contains(&point) {
23678            return None;
23679        }
23680        let display_point = position_map.point_for_position(point).previous_valid;
23681        let anchor = position_map
23682            .snapshot
23683            .display_point_to_anchor(display_point, Bias::Left);
23684        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23685        Some(utf16_offset.0)
23686    }
23687}
23688
23689trait SelectionExt {
23690    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23691    fn spanned_rows(
23692        &self,
23693        include_end_if_at_line_start: bool,
23694        map: &DisplaySnapshot,
23695    ) -> Range<MultiBufferRow>;
23696}
23697
23698impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23699    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23700        let start = self
23701            .start
23702            .to_point(&map.buffer_snapshot)
23703            .to_display_point(map);
23704        let end = self
23705            .end
23706            .to_point(&map.buffer_snapshot)
23707            .to_display_point(map);
23708        if self.reversed {
23709            end..start
23710        } else {
23711            start..end
23712        }
23713    }
23714
23715    fn spanned_rows(
23716        &self,
23717        include_end_if_at_line_start: bool,
23718        map: &DisplaySnapshot,
23719    ) -> Range<MultiBufferRow> {
23720        let start = self.start.to_point(&map.buffer_snapshot);
23721        let mut end = self.end.to_point(&map.buffer_snapshot);
23722        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23723            end.row -= 1;
23724        }
23725
23726        let buffer_start = map.prev_line_boundary(start).0;
23727        let buffer_end = map.next_line_boundary(end).0;
23728        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23729    }
23730}
23731
23732impl<T: InvalidationRegion> InvalidationStack<T> {
23733    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23734    where
23735        S: Clone + ToOffset,
23736    {
23737        while let Some(region) = self.last() {
23738            let all_selections_inside_invalidation_ranges =
23739                if selections.len() == region.ranges().len() {
23740                    selections
23741                        .iter()
23742                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23743                        .all(|(selection, invalidation_range)| {
23744                            let head = selection.head().to_offset(buffer);
23745                            invalidation_range.start <= head && invalidation_range.end >= head
23746                        })
23747                } else {
23748                    false
23749                };
23750
23751            if all_selections_inside_invalidation_ranges {
23752                break;
23753            } else {
23754                self.pop();
23755            }
23756        }
23757    }
23758}
23759
23760impl<T> Default for InvalidationStack<T> {
23761    fn default() -> Self {
23762        Self(Default::default())
23763    }
23764}
23765
23766impl<T> Deref for InvalidationStack<T> {
23767    type Target = Vec<T>;
23768
23769    fn deref(&self) -> &Self::Target {
23770        &self.0
23771    }
23772}
23773
23774impl<T> DerefMut for InvalidationStack<T> {
23775    fn deref_mut(&mut self) -> &mut Self::Target {
23776        &mut self.0
23777    }
23778}
23779
23780impl InvalidationRegion for SnippetState {
23781    fn ranges(&self) -> &[Range<Anchor>] {
23782        &self.ranges[self.active_index]
23783    }
23784}
23785
23786fn edit_prediction_edit_text(
23787    current_snapshot: &BufferSnapshot,
23788    edits: &[(Range<Anchor>, String)],
23789    edit_preview: &EditPreview,
23790    include_deletions: bool,
23791    cx: &App,
23792) -> HighlightedText {
23793    let edits = edits
23794        .iter()
23795        .map(|(anchor, text)| {
23796            (
23797                anchor.start.text_anchor..anchor.end.text_anchor,
23798                text.clone(),
23799            )
23800        })
23801        .collect::<Vec<_>>();
23802
23803    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23804}
23805
23806fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23807    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23808    // Just show the raw edit text with basic styling
23809    let mut text = String::new();
23810    let mut highlights = Vec::new();
23811
23812    let insertion_highlight_style = HighlightStyle {
23813        color: Some(cx.theme().colors().text),
23814        ..Default::default()
23815    };
23816
23817    for (_, edit_text) in edits {
23818        let start_offset = text.len();
23819        text.push_str(edit_text);
23820        let end_offset = text.len();
23821
23822        if start_offset < end_offset {
23823            highlights.push((start_offset..end_offset, insertion_highlight_style));
23824        }
23825    }
23826
23827    HighlightedText {
23828        text: text.into(),
23829        highlights,
23830    }
23831}
23832
23833pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23834    match severity {
23835        lsp::DiagnosticSeverity::ERROR => colors.error,
23836        lsp::DiagnosticSeverity::WARNING => colors.warning,
23837        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23838        lsp::DiagnosticSeverity::HINT => colors.info,
23839        _ => colors.ignored,
23840    }
23841}
23842
23843pub fn styled_runs_for_code_label<'a>(
23844    label: &'a CodeLabel,
23845    syntax_theme: &'a theme::SyntaxTheme,
23846) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23847    let fade_out = HighlightStyle {
23848        fade_out: Some(0.35),
23849        ..Default::default()
23850    };
23851
23852    let mut prev_end = label.filter_range.end;
23853    label
23854        .runs
23855        .iter()
23856        .enumerate()
23857        .flat_map(move |(ix, (range, highlight_id))| {
23858            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23859                style
23860            } else {
23861                return Default::default();
23862            };
23863            let muted_style = style.highlight(fade_out);
23864
23865            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23866            if range.start >= label.filter_range.end {
23867                if range.start > prev_end {
23868                    runs.push((prev_end..range.start, fade_out));
23869                }
23870                runs.push((range.clone(), muted_style));
23871            } else if range.end <= label.filter_range.end {
23872                runs.push((range.clone(), style));
23873            } else {
23874                runs.push((range.start..label.filter_range.end, style));
23875                runs.push((label.filter_range.end..range.end, muted_style));
23876            }
23877            prev_end = cmp::max(prev_end, range.end);
23878
23879            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23880                runs.push((prev_end..label.text.len(), fade_out));
23881            }
23882
23883            runs
23884        })
23885}
23886
23887pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23888    let mut prev_index = 0;
23889    let mut prev_codepoint: Option<char> = None;
23890    text.char_indices()
23891        .chain([(text.len(), '\0')])
23892        .filter_map(move |(index, codepoint)| {
23893            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23894            let is_boundary = index == text.len()
23895                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23896                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23897            if is_boundary {
23898                let chunk = &text[prev_index..index];
23899                prev_index = index;
23900                Some(chunk)
23901            } else {
23902                None
23903            }
23904        })
23905}
23906
23907pub trait RangeToAnchorExt: Sized {
23908    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23909
23910    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23911        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23912        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23913    }
23914}
23915
23916impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23917    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23918        let start_offset = self.start.to_offset(snapshot);
23919        let end_offset = self.end.to_offset(snapshot);
23920        if start_offset == end_offset {
23921            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23922        } else {
23923            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23924        }
23925    }
23926}
23927
23928pub trait RowExt {
23929    fn as_f32(&self) -> f32;
23930
23931    fn next_row(&self) -> Self;
23932
23933    fn previous_row(&self) -> Self;
23934
23935    fn minus(&self, other: Self) -> u32;
23936}
23937
23938impl RowExt for DisplayRow {
23939    fn as_f32(&self) -> f32 {
23940        self.0 as f32
23941    }
23942
23943    fn next_row(&self) -> Self {
23944        Self(self.0 + 1)
23945    }
23946
23947    fn previous_row(&self) -> Self {
23948        Self(self.0.saturating_sub(1))
23949    }
23950
23951    fn minus(&self, other: Self) -> u32 {
23952        self.0 - other.0
23953    }
23954}
23955
23956impl RowExt for MultiBufferRow {
23957    fn as_f32(&self) -> f32 {
23958        self.0 as f32
23959    }
23960
23961    fn next_row(&self) -> Self {
23962        Self(self.0 + 1)
23963    }
23964
23965    fn previous_row(&self) -> Self {
23966        Self(self.0.saturating_sub(1))
23967    }
23968
23969    fn minus(&self, other: Self) -> u32 {
23970        self.0 - other.0
23971    }
23972}
23973
23974trait RowRangeExt {
23975    type Row;
23976
23977    fn len(&self) -> usize;
23978
23979    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23980}
23981
23982impl RowRangeExt for Range<MultiBufferRow> {
23983    type Row = MultiBufferRow;
23984
23985    fn len(&self) -> usize {
23986        (self.end.0 - self.start.0) as usize
23987    }
23988
23989    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23990        (self.start.0..self.end.0).map(MultiBufferRow)
23991    }
23992}
23993
23994impl RowRangeExt for Range<DisplayRow> {
23995    type Row = DisplayRow;
23996
23997    fn len(&self) -> usize {
23998        (self.end.0 - self.start.0) as usize
23999    }
24000
24001    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24002        (self.start.0..self.end.0).map(DisplayRow)
24003    }
24004}
24005
24006/// If select range has more than one line, we
24007/// just point the cursor to range.start.
24008fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24009    if range.start.row == range.end.row {
24010        range
24011    } else {
24012        range.start..range.start
24013    }
24014}
24015pub struct KillRing(ClipboardItem);
24016impl Global for KillRing {}
24017
24018const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24019
24020enum BreakpointPromptEditAction {
24021    Log,
24022    Condition,
24023    HitCondition,
24024}
24025
24026struct BreakpointPromptEditor {
24027    pub(crate) prompt: Entity<Editor>,
24028    editor: WeakEntity<Editor>,
24029    breakpoint_anchor: Anchor,
24030    breakpoint: Breakpoint,
24031    edit_action: BreakpointPromptEditAction,
24032    block_ids: HashSet<CustomBlockId>,
24033    editor_margins: Arc<Mutex<EditorMargins>>,
24034    _subscriptions: Vec<Subscription>,
24035}
24036
24037impl BreakpointPromptEditor {
24038    const MAX_LINES: u8 = 4;
24039
24040    fn new(
24041        editor: WeakEntity<Editor>,
24042        breakpoint_anchor: Anchor,
24043        breakpoint: Breakpoint,
24044        edit_action: BreakpointPromptEditAction,
24045        window: &mut Window,
24046        cx: &mut Context<Self>,
24047    ) -> Self {
24048        let base_text = match edit_action {
24049            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24050            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24051            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24052        }
24053        .map(|msg| msg.to_string())
24054        .unwrap_or_default();
24055
24056        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24057        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24058
24059        let prompt = cx.new(|cx| {
24060            let mut prompt = Editor::new(
24061                EditorMode::AutoHeight {
24062                    min_lines: 1,
24063                    max_lines: Some(Self::MAX_LINES as usize),
24064                },
24065                buffer,
24066                None,
24067                window,
24068                cx,
24069            );
24070            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24071            prompt.set_show_cursor_when_unfocused(false, cx);
24072            prompt.set_placeholder_text(
24073                match edit_action {
24074                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24075                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24076                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24077                },
24078                window,
24079                cx,
24080            );
24081
24082            prompt
24083        });
24084
24085        Self {
24086            prompt,
24087            editor,
24088            breakpoint_anchor,
24089            breakpoint,
24090            edit_action,
24091            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24092            block_ids: Default::default(),
24093            _subscriptions: vec![],
24094        }
24095    }
24096
24097    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24098        self.block_ids.extend(block_ids)
24099    }
24100
24101    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24102        if let Some(editor) = self.editor.upgrade() {
24103            let message = self
24104                .prompt
24105                .read(cx)
24106                .buffer
24107                .read(cx)
24108                .as_singleton()
24109                .expect("A multi buffer in breakpoint prompt isn't possible")
24110                .read(cx)
24111                .as_rope()
24112                .to_string();
24113
24114            editor.update(cx, |editor, cx| {
24115                editor.edit_breakpoint_at_anchor(
24116                    self.breakpoint_anchor,
24117                    self.breakpoint.clone(),
24118                    match self.edit_action {
24119                        BreakpointPromptEditAction::Log => {
24120                            BreakpointEditAction::EditLogMessage(message.into())
24121                        }
24122                        BreakpointPromptEditAction::Condition => {
24123                            BreakpointEditAction::EditCondition(message.into())
24124                        }
24125                        BreakpointPromptEditAction::HitCondition => {
24126                            BreakpointEditAction::EditHitCondition(message.into())
24127                        }
24128                    },
24129                    cx,
24130                );
24131
24132                editor.remove_blocks(self.block_ids.clone(), None, cx);
24133                cx.focus_self(window);
24134            });
24135        }
24136    }
24137
24138    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24139        self.editor
24140            .update(cx, |editor, cx| {
24141                editor.remove_blocks(self.block_ids.clone(), None, cx);
24142                window.focus(&editor.focus_handle);
24143            })
24144            .log_err();
24145    }
24146
24147    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24148        let settings = ThemeSettings::get_global(cx);
24149        let text_style = TextStyle {
24150            color: if self.prompt.read(cx).read_only(cx) {
24151                cx.theme().colors().text_disabled
24152            } else {
24153                cx.theme().colors().text
24154            },
24155            font_family: settings.buffer_font.family.clone(),
24156            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24157            font_size: settings.buffer_font_size(cx).into(),
24158            font_weight: settings.buffer_font.weight,
24159            line_height: relative(settings.buffer_line_height.value()),
24160            ..Default::default()
24161        };
24162        EditorElement::new(
24163            &self.prompt,
24164            EditorStyle {
24165                background: cx.theme().colors().editor_background,
24166                local_player: cx.theme().players().local(),
24167                text: text_style,
24168                ..Default::default()
24169            },
24170        )
24171    }
24172}
24173
24174impl Render for BreakpointPromptEditor {
24175    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24176        let editor_margins = *self.editor_margins.lock();
24177        let gutter_dimensions = editor_margins.gutter;
24178        h_flex()
24179            .key_context("Editor")
24180            .bg(cx.theme().colors().editor_background)
24181            .border_y_1()
24182            .border_color(cx.theme().status().info_border)
24183            .size_full()
24184            .py(window.line_height() / 2.5)
24185            .on_action(cx.listener(Self::confirm))
24186            .on_action(cx.listener(Self::cancel))
24187            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24188            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24189    }
24190}
24191
24192impl Focusable for BreakpointPromptEditor {
24193    fn focus_handle(&self, cx: &App) -> FocusHandle {
24194        self.prompt.focus_handle(cx)
24195    }
24196}
24197
24198fn all_edits_insertions_or_deletions(
24199    edits: &Vec<(Range<Anchor>, String)>,
24200    snapshot: &MultiBufferSnapshot,
24201) -> bool {
24202    let mut all_insertions = true;
24203    let mut all_deletions = true;
24204
24205    for (range, new_text) in edits.iter() {
24206        let range_is_empty = range.to_offset(snapshot).is_empty();
24207        let text_is_empty = new_text.is_empty();
24208
24209        if range_is_empty != text_is_empty {
24210            if range_is_empty {
24211                all_deletions = false;
24212            } else {
24213                all_insertions = false;
24214            }
24215        } else {
24216            return false;
24217        }
24218
24219        if !all_insertions && !all_deletions {
24220            return false;
24221        }
24222    }
24223    all_insertions || all_deletions
24224}
24225
24226struct MissingEditPredictionKeybindingTooltip;
24227
24228impl Render for MissingEditPredictionKeybindingTooltip {
24229    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24230        ui::tooltip_container(window, cx, |container, _, cx| {
24231            container
24232                .flex_shrink_0()
24233                .max_w_80()
24234                .min_h(rems_from_px(124.))
24235                .justify_between()
24236                .child(
24237                    v_flex()
24238                        .flex_1()
24239                        .text_ui_sm(cx)
24240                        .child(Label::new("Conflict with Accept Keybinding"))
24241                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24242                )
24243                .child(
24244                    h_flex()
24245                        .pb_1()
24246                        .gap_1()
24247                        .items_end()
24248                        .w_full()
24249                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24250                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24251                        }))
24252                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24253                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24254                        })),
24255                )
24256        })
24257    }
24258}
24259
24260#[derive(Debug, Clone, Copy, PartialEq)]
24261pub struct LineHighlight {
24262    pub background: Background,
24263    pub border: Option<gpui::Hsla>,
24264    pub include_gutter: bool,
24265    pub type_id: Option<TypeId>,
24266}
24267
24268struct LineManipulationResult {
24269    pub new_text: String,
24270    pub line_count_before: usize,
24271    pub line_count_after: usize,
24272}
24273
24274fn render_diff_hunk_controls(
24275    row: u32,
24276    status: &DiffHunkStatus,
24277    hunk_range: Range<Anchor>,
24278    is_created_file: bool,
24279    line_height: Pixels,
24280    editor: &Entity<Editor>,
24281    _window: &mut Window,
24282    cx: &mut App,
24283) -> AnyElement {
24284    h_flex()
24285        .h(line_height)
24286        .mr_1()
24287        .gap_1()
24288        .px_0p5()
24289        .pb_1()
24290        .border_x_1()
24291        .border_b_1()
24292        .border_color(cx.theme().colors().border_variant)
24293        .rounded_b_lg()
24294        .bg(cx.theme().colors().editor_background)
24295        .gap_1()
24296        .block_mouse_except_scroll()
24297        .shadow_md()
24298        .child(if status.has_secondary_hunk() {
24299            Button::new(("stage", row as u64), "Stage")
24300                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24301                .tooltip({
24302                    let focus_handle = editor.focus_handle(cx);
24303                    move |window, cx| {
24304                        Tooltip::for_action_in(
24305                            "Stage Hunk",
24306                            &::git::ToggleStaged,
24307                            &focus_handle,
24308                            window,
24309                            cx,
24310                        )
24311                    }
24312                })
24313                .on_click({
24314                    let editor = editor.clone();
24315                    move |_event, _window, cx| {
24316                        editor.update(cx, |editor, cx| {
24317                            editor.stage_or_unstage_diff_hunks(
24318                                true,
24319                                vec![hunk_range.start..hunk_range.start],
24320                                cx,
24321                            );
24322                        });
24323                    }
24324                })
24325        } else {
24326            Button::new(("unstage", row as u64), "Unstage")
24327                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24328                .tooltip({
24329                    let focus_handle = editor.focus_handle(cx);
24330                    move |window, cx| {
24331                        Tooltip::for_action_in(
24332                            "Unstage Hunk",
24333                            &::git::ToggleStaged,
24334                            &focus_handle,
24335                            window,
24336                            cx,
24337                        )
24338                    }
24339                })
24340                .on_click({
24341                    let editor = editor.clone();
24342                    move |_event, _window, cx| {
24343                        editor.update(cx, |editor, cx| {
24344                            editor.stage_or_unstage_diff_hunks(
24345                                false,
24346                                vec![hunk_range.start..hunk_range.start],
24347                                cx,
24348                            );
24349                        });
24350                    }
24351                })
24352        })
24353        .child(
24354            Button::new(("restore", row as u64), "Restore")
24355                .tooltip({
24356                    let focus_handle = editor.focus_handle(cx);
24357                    move |window, cx| {
24358                        Tooltip::for_action_in(
24359                            "Restore Hunk",
24360                            &::git::Restore,
24361                            &focus_handle,
24362                            window,
24363                            cx,
24364                        )
24365                    }
24366                })
24367                .on_click({
24368                    let editor = editor.clone();
24369                    move |_event, window, cx| {
24370                        editor.update(cx, |editor, cx| {
24371                            let snapshot = editor.snapshot(window, cx);
24372                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24373                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24374                        });
24375                    }
24376                })
24377                .disabled(is_created_file),
24378        )
24379        .when(
24380            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24381            |el| {
24382                el.child(
24383                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24384                        .shape(IconButtonShape::Square)
24385                        .icon_size(IconSize::Small)
24386                        // .disabled(!has_multiple_hunks)
24387                        .tooltip({
24388                            let focus_handle = editor.focus_handle(cx);
24389                            move |window, cx| {
24390                                Tooltip::for_action_in(
24391                                    "Next Hunk",
24392                                    &GoToHunk,
24393                                    &focus_handle,
24394                                    window,
24395                                    cx,
24396                                )
24397                            }
24398                        })
24399                        .on_click({
24400                            let editor = editor.clone();
24401                            move |_event, window, cx| {
24402                                editor.update(cx, |editor, cx| {
24403                                    let snapshot = editor.snapshot(window, cx);
24404                                    let position =
24405                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24406                                    editor.go_to_hunk_before_or_after_position(
24407                                        &snapshot,
24408                                        position,
24409                                        Direction::Next,
24410                                        window,
24411                                        cx,
24412                                    );
24413                                    editor.expand_selected_diff_hunks(cx);
24414                                });
24415                            }
24416                        }),
24417                )
24418                .child(
24419                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24420                        .shape(IconButtonShape::Square)
24421                        .icon_size(IconSize::Small)
24422                        // .disabled(!has_multiple_hunks)
24423                        .tooltip({
24424                            let focus_handle = editor.focus_handle(cx);
24425                            move |window, cx| {
24426                                Tooltip::for_action_in(
24427                                    "Previous Hunk",
24428                                    &GoToPreviousHunk,
24429                                    &focus_handle,
24430                                    window,
24431                                    cx,
24432                                )
24433                            }
24434                        })
24435                        .on_click({
24436                            let editor = editor.clone();
24437                            move |_event, window, cx| {
24438                                editor.update(cx, |editor, cx| {
24439                                    let snapshot = editor.snapshot(window, cx);
24440                                    let point =
24441                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24442                                    editor.go_to_hunk_before_or_after_position(
24443                                        &snapshot,
24444                                        point,
24445                                        Direction::Prev,
24446                                        window,
24447                                        cx,
24448                                    );
24449                                    editor.expand_selected_diff_hunks(cx);
24450                                });
24451                            }
24452                        }),
24453                )
24454            },
24455        )
24456        .into_any_element()
24457}
24458
24459pub fn multibuffer_context_lines(cx: &App) -> u32 {
24460    EditorSettings::try_get(cx)
24461        .map(|settings| settings.excerpt_context_lines)
24462        .unwrap_or(2)
24463        .min(32)
24464}