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, ShowScrollbar,
   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, ScrollbarAutoHide};
  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::*,
  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, buffer_position) =
 5477            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5478                output
 5479            } else {
 5480                return;
 5481            };
 5482        let buffer_snapshot = buffer.read(cx).snapshot();
 5483
 5484        let query: Option<Arc<String>> =
 5485            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        let mut ignore_word_threshold = false;
 5490        let provider = match requested_source {
 5491            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5492            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5493                ignore_word_threshold = ignore_threshold;
 5494                None
 5495            }
 5496            Some(CompletionsMenuSource::SnippetChoices) => {
 5497                log::error!("bug: SnippetChoices requested_source is not handled");
 5498                None
 5499            }
 5500        };
 5501
 5502        let sort_completions = provider
 5503            .as_ref()
 5504            .is_some_and(|provider| provider.sort_completions());
 5505
 5506        let filter_completions = provider
 5507            .as_ref()
 5508            .is_none_or(|provider| provider.filter_completions());
 5509
 5510        let trigger_kind = match trigger {
 5511            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5512                CompletionTriggerKind::TRIGGER_CHARACTER
 5513            }
 5514            _ => CompletionTriggerKind::INVOKED,
 5515        };
 5516        let completion_context = CompletionContext {
 5517            trigger_character: trigger.and_then(|trigger| {
 5518                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5519                    Some(String::from(trigger))
 5520                } else {
 5521                    None
 5522                }
 5523            }),
 5524            trigger_kind,
 5525        };
 5526
 5527        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5528        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5529        // involve trigger chars, so this is skipped in that case.
 5530        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5531        {
 5532            let menu_is_open = matches!(
 5533                self.context_menu.borrow().as_ref(),
 5534                Some(CodeContextMenu::Completions(_))
 5535            );
 5536            if menu_is_open {
 5537                self.hide_context_menu(window, cx);
 5538            }
 5539        }
 5540
 5541        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5542            if filter_completions {
 5543                menu.filter(query.clone(), provider.clone(), window, cx);
 5544            }
 5545            // When `is_incomplete` is false, no need to re-query completions when the current query
 5546            // is a suffix of the initial query.
 5547            if !menu.is_incomplete {
 5548                // If the new query is a suffix of the old query (typing more characters) and
 5549                // the previous result was complete, the existing completions can be filtered.
 5550                //
 5551                // Note that this is always true for snippet completions.
 5552                let query_matches = match (&menu.initial_query, &query) {
 5553                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5554                    (None, _) => true,
 5555                    _ => false,
 5556                };
 5557                if query_matches {
 5558                    let position_matches = if menu.initial_position == position {
 5559                        true
 5560                    } else {
 5561                        let snapshot = self.buffer.read(cx).read(cx);
 5562                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5563                    };
 5564                    if position_matches {
 5565                        return;
 5566                    }
 5567                }
 5568            }
 5569        };
 5570
 5571        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5572            buffer_snapshot.surrounding_word(buffer_position, false)
 5573        {
 5574            let word_to_exclude = buffer_snapshot
 5575                .text_for_range(word_range.clone())
 5576                .collect::<String>();
 5577            (
 5578                buffer_snapshot.anchor_before(word_range.start)
 5579                    ..buffer_snapshot.anchor_after(buffer_position),
 5580                Some(word_to_exclude),
 5581            )
 5582        } else {
 5583            (buffer_position..buffer_position, None)
 5584        };
 5585
 5586        let language = buffer_snapshot
 5587            .language_at(buffer_position)
 5588            .map(|language| language.name());
 5589
 5590        let completion_settings =
 5591            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5592
 5593        let show_completion_documentation = buffer_snapshot
 5594            .settings_at(buffer_position, cx)
 5595            .show_completion_documentation;
 5596
 5597        // The document can be large, so stay in reasonable bounds when searching for words,
 5598        // otherwise completion pop-up might be slow to appear.
 5599        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5600        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5601        let min_word_search = buffer_snapshot.clip_point(
 5602            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5603            Bias::Left,
 5604        );
 5605        let max_word_search = buffer_snapshot.clip_point(
 5606            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5607            Bias::Right,
 5608        );
 5609        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5610            ..buffer_snapshot.point_to_offset(max_word_search);
 5611
 5612        let skip_digits = query
 5613            .as_ref()
 5614            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5615
 5616        let omit_word_completions = !self.word_completions_enabled
 5617            || (!ignore_word_threshold
 5618                && match &query {
 5619                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5620                    None => completion_settings.words_min_length != 0,
 5621                });
 5622
 5623        let (mut words, provider_responses) = match &provider {
 5624            Some(provider) => {
 5625                let provider_responses = provider.completions(
 5626                    position.excerpt_id,
 5627                    &buffer,
 5628                    buffer_position,
 5629                    completion_context,
 5630                    window,
 5631                    cx,
 5632                );
 5633
 5634                let words = match (omit_word_completions, completion_settings.words) {
 5635                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5636                        Task::ready(BTreeMap::default())
 5637                    }
 5638                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5639                        .background_spawn(async move {
 5640                            buffer_snapshot.words_in_range(WordsQuery {
 5641                                fuzzy_contents: None,
 5642                                range: word_search_range,
 5643                                skip_digits,
 5644                            })
 5645                        }),
 5646                };
 5647
 5648                (words, provider_responses)
 5649            }
 5650            None => {
 5651                let words = if omit_word_completions {
 5652                    Task::ready(BTreeMap::default())
 5653                } else {
 5654                    cx.background_spawn(async move {
 5655                        buffer_snapshot.words_in_range(WordsQuery {
 5656                            fuzzy_contents: None,
 5657                            range: word_search_range,
 5658                            skip_digits,
 5659                        })
 5660                    })
 5661                };
 5662                (words, Task::ready(Ok(Vec::new())))
 5663            }
 5664        };
 5665
 5666        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5667
 5668        let id = post_inc(&mut self.next_completion_id);
 5669        let task = cx.spawn_in(window, async move |editor, cx| {
 5670            let Ok(()) = editor.update(cx, |this, _| {
 5671                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5672            }) else {
 5673                return;
 5674            };
 5675
 5676            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5677            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5678            let mut completions = Vec::new();
 5679            let mut is_incomplete = false;
 5680            let mut display_options: Option<CompletionDisplayOptions> = None;
 5681            if let Some(provider_responses) = provider_responses.await.log_err()
 5682                && !provider_responses.is_empty()
 5683            {
 5684                for response in provider_responses {
 5685                    completions.extend(response.completions);
 5686                    is_incomplete = is_incomplete || response.is_incomplete;
 5687                    match display_options.as_mut() {
 5688                        None => {
 5689                            display_options = Some(response.display_options);
 5690                        }
 5691                        Some(options) => options.merge(&response.display_options),
 5692                    }
 5693                }
 5694                if completion_settings.words == WordsCompletionMode::Fallback {
 5695                    words = Task::ready(BTreeMap::default());
 5696                }
 5697            }
 5698            let display_options = display_options.unwrap_or_default();
 5699
 5700            let mut words = words.await;
 5701            if let Some(word_to_exclude) = &word_to_exclude {
 5702                words.remove(word_to_exclude);
 5703            }
 5704            for lsp_completion in &completions {
 5705                words.remove(&lsp_completion.new_text);
 5706            }
 5707            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5708                replace_range: word_replace_range.clone(),
 5709                new_text: word.clone(),
 5710                label: CodeLabel::plain(word, None),
 5711                icon_path: None,
 5712                documentation: None,
 5713                source: CompletionSource::BufferWord {
 5714                    word_range,
 5715                    resolved: false,
 5716                },
 5717                insert_text_mode: Some(InsertTextMode::AS_IS),
 5718                confirm: None,
 5719            }));
 5720
 5721            let menu = if completions.is_empty() {
 5722                None
 5723            } else {
 5724                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5725                    let languages = editor
 5726                        .workspace
 5727                        .as_ref()
 5728                        .and_then(|(workspace, _)| workspace.upgrade())
 5729                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5730                    let menu = CompletionsMenu::new(
 5731                        id,
 5732                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5733                        sort_completions,
 5734                        show_completion_documentation,
 5735                        position,
 5736                        query.clone(),
 5737                        is_incomplete,
 5738                        buffer.clone(),
 5739                        completions.into(),
 5740                        display_options,
 5741                        snippet_sort_order,
 5742                        languages,
 5743                        language,
 5744                        cx,
 5745                    );
 5746
 5747                    let query = if filter_completions { query } else { None };
 5748                    let matches_task = if let Some(query) = query {
 5749                        menu.do_async_filtering(query, cx)
 5750                    } else {
 5751                        Task::ready(menu.unfiltered_matches())
 5752                    };
 5753                    (menu, matches_task)
 5754                }) else {
 5755                    return;
 5756                };
 5757
 5758                let matches = matches_task.await;
 5759
 5760                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5761                    // Newer menu already set, so exit.
 5762                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5763                        editor.context_menu.borrow().as_ref()
 5764                        && prev_menu.id > id
 5765                    {
 5766                        return;
 5767                    };
 5768
 5769                    // Only valid to take prev_menu because it the new menu is immediately set
 5770                    // below, or the menu is hidden.
 5771                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5772                        editor.context_menu.borrow_mut().take()
 5773                    {
 5774                        let position_matches =
 5775                            if prev_menu.initial_position == menu.initial_position {
 5776                                true
 5777                            } else {
 5778                                let snapshot = editor.buffer.read(cx).read(cx);
 5779                                prev_menu.initial_position.to_offset(&snapshot)
 5780                                    == menu.initial_position.to_offset(&snapshot)
 5781                            };
 5782                        if position_matches {
 5783                            // Preserve markdown cache before `set_filter_results` because it will
 5784                            // try to populate the documentation cache.
 5785                            menu.preserve_markdown_cache(prev_menu);
 5786                        }
 5787                    };
 5788
 5789                    menu.set_filter_results(matches, provider, window, cx);
 5790                }) else {
 5791                    return;
 5792                };
 5793
 5794                menu.visible().then_some(menu)
 5795            };
 5796
 5797            editor
 5798                .update_in(cx, |editor, window, cx| {
 5799                    if editor.focus_handle.is_focused(window)
 5800                        && let Some(menu) = menu
 5801                    {
 5802                        *editor.context_menu.borrow_mut() =
 5803                            Some(CodeContextMenu::Completions(menu));
 5804
 5805                        crate::hover_popover::hide_hover(editor, cx);
 5806                        if editor.show_edit_predictions_in_menu() {
 5807                            editor.update_visible_edit_prediction(window, cx);
 5808                        } else {
 5809                            editor.discard_edit_prediction(false, cx);
 5810                        }
 5811
 5812                        cx.notify();
 5813                        return;
 5814                    }
 5815
 5816                    if editor.completion_tasks.len() <= 1 {
 5817                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5818                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5819                        // If it was already hidden and we don't show edit predictions in the menu,
 5820                        // we should also show the edit prediction when available.
 5821                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5822                            editor.update_visible_edit_prediction(window, cx);
 5823                        }
 5824                    }
 5825                })
 5826                .ok();
 5827        });
 5828
 5829        self.completion_tasks.push((id, task));
 5830    }
 5831
 5832    #[cfg(feature = "test-support")]
 5833    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5834        let menu = self.context_menu.borrow();
 5835        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5836            let completions = menu.completions.borrow();
 5837            Some(completions.to_vec())
 5838        } else {
 5839            None
 5840        }
 5841    }
 5842
 5843    pub fn with_completions_menu_matching_id<R>(
 5844        &self,
 5845        id: CompletionId,
 5846        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5847    ) -> R {
 5848        let mut context_menu = self.context_menu.borrow_mut();
 5849        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5850            return f(None);
 5851        };
 5852        if completions_menu.id != id {
 5853            return f(None);
 5854        }
 5855        f(Some(completions_menu))
 5856    }
 5857
 5858    pub fn confirm_completion(
 5859        &mut self,
 5860        action: &ConfirmCompletion,
 5861        window: &mut Window,
 5862        cx: &mut Context<Self>,
 5863    ) -> Option<Task<Result<()>>> {
 5864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5865        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5866    }
 5867
 5868    pub fn confirm_completion_insert(
 5869        &mut self,
 5870        _: &ConfirmCompletionInsert,
 5871        window: &mut Window,
 5872        cx: &mut Context<Self>,
 5873    ) -> Option<Task<Result<()>>> {
 5874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5875        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5876    }
 5877
 5878    pub fn confirm_completion_replace(
 5879        &mut self,
 5880        _: &ConfirmCompletionReplace,
 5881        window: &mut Window,
 5882        cx: &mut Context<Self>,
 5883    ) -> Option<Task<Result<()>>> {
 5884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5885        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5886    }
 5887
 5888    pub fn compose_completion(
 5889        &mut self,
 5890        action: &ComposeCompletion,
 5891        window: &mut Window,
 5892        cx: &mut Context<Self>,
 5893    ) -> Option<Task<Result<()>>> {
 5894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5895        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5896    }
 5897
 5898    fn do_completion(
 5899        &mut self,
 5900        item_ix: Option<usize>,
 5901        intent: CompletionIntent,
 5902        window: &mut Window,
 5903        cx: &mut Context<Editor>,
 5904    ) -> Option<Task<Result<()>>> {
 5905        use language::ToOffset as _;
 5906
 5907        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5908        else {
 5909            return None;
 5910        };
 5911
 5912        let candidate_id = {
 5913            let entries = completions_menu.entries.borrow();
 5914            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5915            if self.show_edit_predictions_in_menu() {
 5916                self.discard_edit_prediction(true, cx);
 5917            }
 5918            mat.candidate_id
 5919        };
 5920
 5921        let completion = completions_menu
 5922            .completions
 5923            .borrow()
 5924            .get(candidate_id)?
 5925            .clone();
 5926        cx.stop_propagation();
 5927
 5928        let buffer_handle = completions_menu.buffer.clone();
 5929
 5930        let CompletionEdit {
 5931            new_text,
 5932            snippet,
 5933            replace_range,
 5934        } = process_completion_for_edit(
 5935            &completion,
 5936            intent,
 5937            &buffer_handle,
 5938            &completions_menu.initial_position.text_anchor,
 5939            cx,
 5940        );
 5941
 5942        let buffer = buffer_handle.read(cx);
 5943        let snapshot = self.buffer.read(cx).snapshot(cx);
 5944        let newest_anchor = self.selections.newest_anchor();
 5945        let replace_range_multibuffer = {
 5946            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5947            let multibuffer_anchor = snapshot
 5948                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5949                .unwrap()
 5950                ..snapshot
 5951                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5952                    .unwrap();
 5953            multibuffer_anchor.start.to_offset(&snapshot)
 5954                ..multibuffer_anchor.end.to_offset(&snapshot)
 5955        };
 5956        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5957            return None;
 5958        }
 5959
 5960        let old_text = buffer
 5961            .text_for_range(replace_range.clone())
 5962            .collect::<String>();
 5963        let lookbehind = newest_anchor
 5964            .start
 5965            .text_anchor
 5966            .to_offset(buffer)
 5967            .saturating_sub(replace_range.start);
 5968        let lookahead = replace_range
 5969            .end
 5970            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5971        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5972        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5973
 5974        let selections = self.selections.all::<usize>(cx);
 5975        let mut ranges = Vec::new();
 5976        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5977
 5978        for selection in &selections {
 5979            let range = if selection.id == newest_anchor.id {
 5980                replace_range_multibuffer.clone()
 5981            } else {
 5982                let mut range = selection.range();
 5983
 5984                // if prefix is present, don't duplicate it
 5985                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5986                    range.start = range.start.saturating_sub(lookbehind);
 5987
 5988                    // if suffix is also present, mimic the newest cursor and replace it
 5989                    if selection.id != newest_anchor.id
 5990                        && snapshot.contains_str_at(range.end, suffix)
 5991                    {
 5992                        range.end += lookahead;
 5993                    }
 5994                }
 5995                range
 5996            };
 5997
 5998            ranges.push(range.clone());
 5999
 6000            if !self.linked_edit_ranges.is_empty() {
 6001                let start_anchor = snapshot.anchor_before(range.start);
 6002                let end_anchor = snapshot.anchor_after(range.end);
 6003                if let Some(ranges) = self
 6004                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6005                {
 6006                    for (buffer, edits) in ranges {
 6007                        linked_edits
 6008                            .entry(buffer.clone())
 6009                            .or_default()
 6010                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6011                    }
 6012                }
 6013            }
 6014        }
 6015
 6016        let common_prefix_len = old_text
 6017            .chars()
 6018            .zip(new_text.chars())
 6019            .take_while(|(a, b)| a == b)
 6020            .map(|(a, _)| a.len_utf8())
 6021            .sum::<usize>();
 6022
 6023        cx.emit(EditorEvent::InputHandled {
 6024            utf16_range_to_replace: None,
 6025            text: new_text[common_prefix_len..].into(),
 6026        });
 6027
 6028        self.transact(window, cx, |editor, window, cx| {
 6029            if let Some(mut snippet) = snippet {
 6030                snippet.text = new_text.to_string();
 6031                editor
 6032                    .insert_snippet(&ranges, snippet, window, cx)
 6033                    .log_err();
 6034            } else {
 6035                editor.buffer.update(cx, |multi_buffer, cx| {
 6036                    let auto_indent = match completion.insert_text_mode {
 6037                        Some(InsertTextMode::AS_IS) => None,
 6038                        _ => editor.autoindent_mode.clone(),
 6039                    };
 6040                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6041                    multi_buffer.edit(edits, auto_indent, cx);
 6042                });
 6043            }
 6044            for (buffer, edits) in linked_edits {
 6045                buffer.update(cx, |buffer, cx| {
 6046                    let snapshot = buffer.snapshot();
 6047                    let edits = edits
 6048                        .into_iter()
 6049                        .map(|(range, text)| {
 6050                            use text::ToPoint as TP;
 6051                            let end_point = TP::to_point(&range.end, &snapshot);
 6052                            let start_point = TP::to_point(&range.start, &snapshot);
 6053                            (start_point..end_point, text)
 6054                        })
 6055                        .sorted_by_key(|(range, _)| range.start);
 6056                    buffer.edit(edits, None, cx);
 6057                })
 6058            }
 6059
 6060            editor.refresh_edit_prediction(true, false, window, cx);
 6061        });
 6062        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6063
 6064        let show_new_completions_on_confirm = completion
 6065            .confirm
 6066            .as_ref()
 6067            .is_some_and(|confirm| confirm(intent, window, cx));
 6068        if show_new_completions_on_confirm {
 6069            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6070        }
 6071
 6072        let provider = self.completion_provider.as_ref()?;
 6073        drop(completion);
 6074        let apply_edits = provider.apply_additional_edits_for_completion(
 6075            buffer_handle,
 6076            completions_menu.completions.clone(),
 6077            candidate_id,
 6078            true,
 6079            cx,
 6080        );
 6081
 6082        let editor_settings = EditorSettings::get_global(cx);
 6083        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6084            // After the code completion is finished, users often want to know what signatures are needed.
 6085            // so we should automatically call signature_help
 6086            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6087        }
 6088
 6089        Some(cx.foreground_executor().spawn(async move {
 6090            apply_edits.await?;
 6091            Ok(())
 6092        }))
 6093    }
 6094
 6095    pub fn toggle_code_actions(
 6096        &mut self,
 6097        action: &ToggleCodeActions,
 6098        window: &mut Window,
 6099        cx: &mut Context<Self>,
 6100    ) {
 6101        let quick_launch = action.quick_launch;
 6102        let mut context_menu = self.context_menu.borrow_mut();
 6103        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6104            if code_actions.deployed_from == action.deployed_from {
 6105                // Toggle if we're selecting the same one
 6106                *context_menu = None;
 6107                cx.notify();
 6108                return;
 6109            } else {
 6110                // Otherwise, clear it and start a new one
 6111                *context_menu = None;
 6112                cx.notify();
 6113            }
 6114        }
 6115        drop(context_menu);
 6116        let snapshot = self.snapshot(window, cx);
 6117        let deployed_from = action.deployed_from.clone();
 6118        let action = action.clone();
 6119        self.completion_tasks.clear();
 6120        self.discard_edit_prediction(false, cx);
 6121
 6122        let multibuffer_point = match &action.deployed_from {
 6123            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6124                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6125            }
 6126            _ => self.selections.newest::<Point>(cx).head(),
 6127        };
 6128        let Some((buffer, buffer_row)) = snapshot
 6129            .buffer_snapshot
 6130            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6131            .and_then(|(buffer_snapshot, range)| {
 6132                self.buffer()
 6133                    .read(cx)
 6134                    .buffer(buffer_snapshot.remote_id())
 6135                    .map(|buffer| (buffer, range.start.row))
 6136            })
 6137        else {
 6138            return;
 6139        };
 6140        let buffer_id = buffer.read(cx).remote_id();
 6141        let tasks = self
 6142            .tasks
 6143            .get(&(buffer_id, buffer_row))
 6144            .map(|t| Arc::new(t.to_owned()));
 6145
 6146        if !self.focus_handle.is_focused(window) {
 6147            return;
 6148        }
 6149        let project = self.project.clone();
 6150
 6151        let code_actions_task = match deployed_from {
 6152            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6153            _ => self.code_actions(buffer_row, window, cx),
 6154        };
 6155
 6156        let runnable_task = match deployed_from {
 6157            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6158            _ => {
 6159                let mut task_context_task = Task::ready(None);
 6160                if let Some(tasks) = &tasks
 6161                    && let Some(project) = project
 6162                {
 6163                    task_context_task =
 6164                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6165                }
 6166
 6167                cx.spawn_in(window, {
 6168                    let buffer = buffer.clone();
 6169                    async move |editor, cx| {
 6170                        let task_context = task_context_task.await;
 6171
 6172                        let resolved_tasks =
 6173                            tasks
 6174                                .zip(task_context.clone())
 6175                                .map(|(tasks, task_context)| ResolvedTasks {
 6176                                    templates: tasks.resolve(&task_context).collect(),
 6177                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6178                                        multibuffer_point.row,
 6179                                        tasks.column,
 6180                                    )),
 6181                                });
 6182                        let debug_scenarios = editor
 6183                            .update(cx, |editor, cx| {
 6184                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6185                            })?
 6186                            .await;
 6187                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6188                    }
 6189                })
 6190            }
 6191        };
 6192
 6193        cx.spawn_in(window, async move |editor, cx| {
 6194            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6195            let code_actions = code_actions_task.await;
 6196            let spawn_straight_away = quick_launch
 6197                && resolved_tasks
 6198                    .as_ref()
 6199                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6200                && code_actions
 6201                    .as_ref()
 6202                    .is_none_or(|actions| actions.is_empty())
 6203                && debug_scenarios.is_empty();
 6204
 6205            editor.update_in(cx, |editor, window, cx| {
 6206                crate::hover_popover::hide_hover(editor, cx);
 6207                let actions = CodeActionContents::new(
 6208                    resolved_tasks,
 6209                    code_actions,
 6210                    debug_scenarios,
 6211                    task_context.unwrap_or_default(),
 6212                );
 6213
 6214                // Don't show the menu if there are no actions available
 6215                if actions.is_empty() {
 6216                    cx.notify();
 6217                    return Task::ready(Ok(()));
 6218                }
 6219
 6220                *editor.context_menu.borrow_mut() =
 6221                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6222                        buffer,
 6223                        actions,
 6224                        selected_item: Default::default(),
 6225                        scroll_handle: UniformListScrollHandle::default(),
 6226                        deployed_from,
 6227                    }));
 6228                cx.notify();
 6229                if spawn_straight_away
 6230                    && let Some(task) = editor.confirm_code_action(
 6231                        &ConfirmCodeAction { item_ix: Some(0) },
 6232                        window,
 6233                        cx,
 6234                    )
 6235                {
 6236                    return task;
 6237                }
 6238
 6239                Task::ready(Ok(()))
 6240            })
 6241        })
 6242        .detach_and_log_err(cx);
 6243    }
 6244
 6245    fn debug_scenarios(
 6246        &mut self,
 6247        resolved_tasks: &Option<ResolvedTasks>,
 6248        buffer: &Entity<Buffer>,
 6249        cx: &mut App,
 6250    ) -> Task<Vec<task::DebugScenario>> {
 6251        maybe!({
 6252            let project = self.project()?;
 6253            let dap_store = project.read(cx).dap_store();
 6254            let mut scenarios = vec![];
 6255            let resolved_tasks = resolved_tasks.as_ref()?;
 6256            let buffer = buffer.read(cx);
 6257            let language = buffer.language()?;
 6258            let file = buffer.file();
 6259            let debug_adapter = language_settings(language.name().into(), file, cx)
 6260                .debuggers
 6261                .first()
 6262                .map(SharedString::from)
 6263                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6264
 6265            dap_store.update(cx, |dap_store, cx| {
 6266                for (_, task) in &resolved_tasks.templates {
 6267                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6268                        task.original_task().clone(),
 6269                        debug_adapter.clone().into(),
 6270                        task.display_label().to_owned().into(),
 6271                        cx,
 6272                    );
 6273                    scenarios.push(maybe_scenario);
 6274                }
 6275            });
 6276            Some(cx.background_spawn(async move {
 6277                futures::future::join_all(scenarios)
 6278                    .await
 6279                    .into_iter()
 6280                    .flatten()
 6281                    .collect::<Vec<_>>()
 6282            }))
 6283        })
 6284        .unwrap_or_else(|| Task::ready(vec![]))
 6285    }
 6286
 6287    fn code_actions(
 6288        &mut self,
 6289        buffer_row: u32,
 6290        window: &mut Window,
 6291        cx: &mut Context<Self>,
 6292    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6293        let mut task = self.code_actions_task.take();
 6294        cx.spawn_in(window, async move |editor, cx| {
 6295            while let Some(prev_task) = task {
 6296                prev_task.await.log_err();
 6297                task = editor
 6298                    .update(cx, |this, _| this.code_actions_task.take())
 6299                    .ok()?;
 6300            }
 6301
 6302            editor
 6303                .update(cx, |editor, cx| {
 6304                    editor
 6305                        .available_code_actions
 6306                        .clone()
 6307                        .and_then(|(location, code_actions)| {
 6308                            let snapshot = location.buffer.read(cx).snapshot();
 6309                            let point_range = location.range.to_point(&snapshot);
 6310                            let point_range = point_range.start.row..=point_range.end.row;
 6311                            if point_range.contains(&buffer_row) {
 6312                                Some(code_actions)
 6313                            } else {
 6314                                None
 6315                            }
 6316                        })
 6317                })
 6318                .ok()
 6319                .flatten()
 6320        })
 6321    }
 6322
 6323    pub fn confirm_code_action(
 6324        &mut self,
 6325        action: &ConfirmCodeAction,
 6326        window: &mut Window,
 6327        cx: &mut Context<Self>,
 6328    ) -> Option<Task<Result<()>>> {
 6329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6330
 6331        let actions_menu =
 6332            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6333                menu
 6334            } else {
 6335                return None;
 6336            };
 6337
 6338        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6339        let action = actions_menu.actions.get(action_ix)?;
 6340        let title = action.label();
 6341        let buffer = actions_menu.buffer;
 6342        let workspace = self.workspace()?;
 6343
 6344        match action {
 6345            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6346                workspace.update(cx, |workspace, cx| {
 6347                    workspace.schedule_resolved_task(
 6348                        task_source_kind,
 6349                        resolved_task,
 6350                        false,
 6351                        window,
 6352                        cx,
 6353                    );
 6354
 6355                    Some(Task::ready(Ok(())))
 6356                })
 6357            }
 6358            CodeActionsItem::CodeAction {
 6359                excerpt_id,
 6360                action,
 6361                provider,
 6362            } => {
 6363                let apply_code_action =
 6364                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6365                let workspace = workspace.downgrade();
 6366                Some(cx.spawn_in(window, async move |editor, cx| {
 6367                    let project_transaction = apply_code_action.await?;
 6368                    Self::open_project_transaction(
 6369                        &editor,
 6370                        workspace,
 6371                        project_transaction,
 6372                        title,
 6373                        cx,
 6374                    )
 6375                    .await
 6376                }))
 6377            }
 6378            CodeActionsItem::DebugScenario(scenario) => {
 6379                let context = actions_menu.actions.context;
 6380
 6381                workspace.update(cx, |workspace, cx| {
 6382                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6383                    workspace.start_debug_session(
 6384                        scenario,
 6385                        context,
 6386                        Some(buffer),
 6387                        None,
 6388                        window,
 6389                        cx,
 6390                    );
 6391                });
 6392                Some(Task::ready(Ok(())))
 6393            }
 6394        }
 6395    }
 6396
 6397    pub async fn open_project_transaction(
 6398        editor: &WeakEntity<Editor>,
 6399        workspace: WeakEntity<Workspace>,
 6400        transaction: ProjectTransaction,
 6401        title: String,
 6402        cx: &mut AsyncWindowContext,
 6403    ) -> Result<()> {
 6404        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6405        cx.update(|_, cx| {
 6406            entries.sort_unstable_by_key(|(buffer, _)| {
 6407                buffer.read(cx).file().map(|f| f.path().clone())
 6408            });
 6409        })?;
 6410
 6411        // If the project transaction's edits are all contained within this editor, then
 6412        // avoid opening a new editor to display them.
 6413
 6414        if let Some((buffer, transaction)) = entries.first() {
 6415            if entries.len() == 1 {
 6416                let excerpt = editor.update(cx, |editor, cx| {
 6417                    editor
 6418                        .buffer()
 6419                        .read(cx)
 6420                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6421                })?;
 6422                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6423                    && excerpted_buffer == *buffer
 6424                {
 6425                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6426                        let excerpt_range = excerpt_range.to_offset(buffer);
 6427                        buffer
 6428                            .edited_ranges_for_transaction::<usize>(transaction)
 6429                            .all(|range| {
 6430                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6431                            })
 6432                    })?;
 6433
 6434                    if all_edits_within_excerpt {
 6435                        return Ok(());
 6436                    }
 6437                }
 6438            }
 6439        } else {
 6440            return Ok(());
 6441        }
 6442
 6443        let mut ranges_to_highlight = Vec::new();
 6444        let excerpt_buffer = cx.new(|cx| {
 6445            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6446            for (buffer_handle, transaction) in &entries {
 6447                let edited_ranges = buffer_handle
 6448                    .read(cx)
 6449                    .edited_ranges_for_transaction::<Point>(transaction)
 6450                    .collect::<Vec<_>>();
 6451                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6452                    PathKey::for_buffer(buffer_handle, cx),
 6453                    buffer_handle.clone(),
 6454                    edited_ranges,
 6455                    multibuffer_context_lines(cx),
 6456                    cx,
 6457                );
 6458
 6459                ranges_to_highlight.extend(ranges);
 6460            }
 6461            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6462            multibuffer
 6463        })?;
 6464
 6465        workspace.update_in(cx, |workspace, window, cx| {
 6466            let project = workspace.project().clone();
 6467            let editor =
 6468                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6469            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6470            editor.update(cx, |editor, cx| {
 6471                editor.highlight_background::<Self>(
 6472                    &ranges_to_highlight,
 6473                    |theme| theme.colors().editor_highlighted_line_background,
 6474                    cx,
 6475                );
 6476            });
 6477        })?;
 6478
 6479        Ok(())
 6480    }
 6481
 6482    pub fn clear_code_action_providers(&mut self) {
 6483        self.code_action_providers.clear();
 6484        self.available_code_actions.take();
 6485    }
 6486
 6487    pub fn add_code_action_provider(
 6488        &mut self,
 6489        provider: Rc<dyn CodeActionProvider>,
 6490        window: &mut Window,
 6491        cx: &mut Context<Self>,
 6492    ) {
 6493        if self
 6494            .code_action_providers
 6495            .iter()
 6496            .any(|existing_provider| existing_provider.id() == provider.id())
 6497        {
 6498            return;
 6499        }
 6500
 6501        self.code_action_providers.push(provider);
 6502        self.refresh_code_actions(window, cx);
 6503    }
 6504
 6505    pub fn remove_code_action_provider(
 6506        &mut self,
 6507        id: Arc<str>,
 6508        window: &mut Window,
 6509        cx: &mut Context<Self>,
 6510    ) {
 6511        self.code_action_providers
 6512            .retain(|provider| provider.id() != id);
 6513        self.refresh_code_actions(window, cx);
 6514    }
 6515
 6516    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6517        !self.code_action_providers.is_empty()
 6518            && EditorSettings::get_global(cx).toolbar.code_actions
 6519    }
 6520
 6521    pub fn has_available_code_actions(&self) -> bool {
 6522        self.available_code_actions
 6523            .as_ref()
 6524            .is_some_and(|(_, actions)| !actions.is_empty())
 6525    }
 6526
 6527    fn render_inline_code_actions(
 6528        &self,
 6529        icon_size: ui::IconSize,
 6530        display_row: DisplayRow,
 6531        is_active: bool,
 6532        cx: &mut Context<Self>,
 6533    ) -> AnyElement {
 6534        let show_tooltip = !self.context_menu_visible();
 6535        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6536            .icon_size(icon_size)
 6537            .shape(ui::IconButtonShape::Square)
 6538            .icon_color(ui::Color::Hidden)
 6539            .toggle_state(is_active)
 6540            .when(show_tooltip, |this| {
 6541                this.tooltip({
 6542                    let focus_handle = self.focus_handle.clone();
 6543                    move |window, cx| {
 6544                        Tooltip::for_action_in(
 6545                            "Toggle Code Actions",
 6546                            &ToggleCodeActions {
 6547                                deployed_from: None,
 6548                                quick_launch: false,
 6549                            },
 6550                            &focus_handle,
 6551                            window,
 6552                            cx,
 6553                        )
 6554                    }
 6555                })
 6556            })
 6557            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6558                window.focus(&editor.focus_handle(cx));
 6559                editor.toggle_code_actions(
 6560                    &crate::actions::ToggleCodeActions {
 6561                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6562                            display_row,
 6563                        )),
 6564                        quick_launch: false,
 6565                    },
 6566                    window,
 6567                    cx,
 6568                );
 6569            }))
 6570            .into_any_element()
 6571    }
 6572
 6573    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6574        &self.context_menu
 6575    }
 6576
 6577    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6578        let newest_selection = self.selections.newest_anchor().clone();
 6579        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6580        let buffer = self.buffer.read(cx);
 6581        if newest_selection.head().diff_base_anchor.is_some() {
 6582            return None;
 6583        }
 6584        let (start_buffer, start) =
 6585            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6586        let (end_buffer, end) =
 6587            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6588        if start_buffer != end_buffer {
 6589            return None;
 6590        }
 6591
 6592        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6593            cx.background_executor()
 6594                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6595                .await;
 6596
 6597            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6598                let providers = this.code_action_providers.clone();
 6599                let tasks = this
 6600                    .code_action_providers
 6601                    .iter()
 6602                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6603                    .collect::<Vec<_>>();
 6604                (providers, tasks)
 6605            })?;
 6606
 6607            let mut actions = Vec::new();
 6608            for (provider, provider_actions) in
 6609                providers.into_iter().zip(future::join_all(tasks).await)
 6610            {
 6611                if let Some(provider_actions) = provider_actions.log_err() {
 6612                    actions.extend(provider_actions.into_iter().map(|action| {
 6613                        AvailableCodeAction {
 6614                            excerpt_id: newest_selection.start.excerpt_id,
 6615                            action,
 6616                            provider: provider.clone(),
 6617                        }
 6618                    }));
 6619                }
 6620            }
 6621
 6622            this.update(cx, |this, cx| {
 6623                this.available_code_actions = if actions.is_empty() {
 6624                    None
 6625                } else {
 6626                    Some((
 6627                        Location {
 6628                            buffer: start_buffer,
 6629                            range: start..end,
 6630                        },
 6631                        actions.into(),
 6632                    ))
 6633                };
 6634                cx.notify();
 6635            })
 6636        }));
 6637        None
 6638    }
 6639
 6640    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6641        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6642            self.show_git_blame_inline = false;
 6643
 6644            self.show_git_blame_inline_delay_task =
 6645                Some(cx.spawn_in(window, async move |this, cx| {
 6646                    cx.background_executor().timer(delay).await;
 6647
 6648                    this.update(cx, |this, cx| {
 6649                        this.show_git_blame_inline = true;
 6650                        cx.notify();
 6651                    })
 6652                    .log_err();
 6653                }));
 6654        }
 6655    }
 6656
 6657    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6658        let snapshot = self.snapshot(window, cx);
 6659        let cursor = self.selections.newest::<Point>(cx).head();
 6660        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6661        else {
 6662            return;
 6663        };
 6664
 6665        let Some(blame) = self.blame.as_ref() else {
 6666            return;
 6667        };
 6668
 6669        let row_info = RowInfo {
 6670            buffer_id: Some(buffer.remote_id()),
 6671            buffer_row: Some(point.row),
 6672            ..Default::default()
 6673        };
 6674        let Some((buffer, blame_entry)) = blame
 6675            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6676            .flatten()
 6677        else {
 6678            return;
 6679        };
 6680
 6681        let anchor = self.selections.newest_anchor().head();
 6682        let position = self.to_pixel_point(anchor, &snapshot, window);
 6683        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6684            self.show_blame_popover(
 6685                buffer,
 6686                &blame_entry,
 6687                position + last_bounds.origin,
 6688                true,
 6689                cx,
 6690            );
 6691        };
 6692    }
 6693
 6694    fn show_blame_popover(
 6695        &mut self,
 6696        buffer: BufferId,
 6697        blame_entry: &BlameEntry,
 6698        position: gpui::Point<Pixels>,
 6699        ignore_timeout: bool,
 6700        cx: &mut Context<Self>,
 6701    ) {
 6702        if let Some(state) = &mut self.inline_blame_popover {
 6703            state.hide_task.take();
 6704        } else {
 6705            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6706            let blame_entry = blame_entry.clone();
 6707            let show_task = cx.spawn(async move |editor, cx| {
 6708                if !ignore_timeout {
 6709                    cx.background_executor()
 6710                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6711                        .await;
 6712                }
 6713                editor
 6714                    .update(cx, |editor, cx| {
 6715                        editor.inline_blame_popover_show_task.take();
 6716                        let Some(blame) = editor.blame.as_ref() else {
 6717                            return;
 6718                        };
 6719                        let blame = blame.read(cx);
 6720                        let details = blame.details_for_entry(buffer, &blame_entry);
 6721                        let markdown = cx.new(|cx| {
 6722                            Markdown::new(
 6723                                details
 6724                                    .as_ref()
 6725                                    .map(|message| message.message.clone())
 6726                                    .unwrap_or_default(),
 6727                                None,
 6728                                None,
 6729                                cx,
 6730                            )
 6731                        });
 6732                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6733                            position,
 6734                            hide_task: None,
 6735                            popover_bounds: None,
 6736                            popover_state: InlineBlamePopoverState {
 6737                                scroll_handle: ScrollHandle::new(),
 6738                                commit_message: details,
 6739                                markdown,
 6740                            },
 6741                            keyboard_grace: ignore_timeout,
 6742                        });
 6743                        cx.notify();
 6744                    })
 6745                    .ok();
 6746            });
 6747            self.inline_blame_popover_show_task = Some(show_task);
 6748        }
 6749    }
 6750
 6751    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6752        self.inline_blame_popover_show_task.take();
 6753        if let Some(state) = &mut self.inline_blame_popover {
 6754            let hide_task = cx.spawn(async move |editor, cx| {
 6755                cx.background_executor()
 6756                    .timer(std::time::Duration::from_millis(100))
 6757                    .await;
 6758                editor
 6759                    .update(cx, |editor, cx| {
 6760                        editor.inline_blame_popover.take();
 6761                        cx.notify();
 6762                    })
 6763                    .ok();
 6764            });
 6765            state.hide_task = Some(hide_task);
 6766        }
 6767    }
 6768
 6769    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6770        if self.pending_rename.is_some() {
 6771            return None;
 6772        }
 6773
 6774        let provider = self.semantics_provider.clone()?;
 6775        let buffer = self.buffer.read(cx);
 6776        let newest_selection = self.selections.newest_anchor().clone();
 6777        let cursor_position = newest_selection.head();
 6778        let (cursor_buffer, cursor_buffer_position) =
 6779            buffer.text_anchor_for_position(cursor_position, cx)?;
 6780        let (tail_buffer, tail_buffer_position) =
 6781            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6782        if cursor_buffer != tail_buffer {
 6783            return None;
 6784        }
 6785
 6786        let snapshot = cursor_buffer.read(cx).snapshot();
 6787        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6788        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6789        if start_word_range != end_word_range {
 6790            self.document_highlights_task.take();
 6791            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6792            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6793            return None;
 6794        }
 6795
 6796        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6797        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6798            cx.background_executor()
 6799                .timer(Duration::from_millis(debounce))
 6800                .await;
 6801
 6802            let highlights = if let Some(highlights) = cx
 6803                .update(|cx| {
 6804                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6805                })
 6806                .ok()
 6807                .flatten()
 6808            {
 6809                highlights.await.log_err()
 6810            } else {
 6811                None
 6812            };
 6813
 6814            if let Some(highlights) = highlights {
 6815                this.update(cx, |this, cx| {
 6816                    if this.pending_rename.is_some() {
 6817                        return;
 6818                    }
 6819
 6820                    let buffer = this.buffer.read(cx);
 6821                    if buffer
 6822                        .text_anchor_for_position(cursor_position, cx)
 6823                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6824                    {
 6825                        return;
 6826                    }
 6827
 6828                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6829                    let mut write_ranges = Vec::new();
 6830                    let mut read_ranges = Vec::new();
 6831                    for highlight in highlights {
 6832                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6833                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6834                        {
 6835                            let start = highlight
 6836                                .range
 6837                                .start
 6838                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6839                            let end = highlight
 6840                                .range
 6841                                .end
 6842                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6843                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6844                                continue;
 6845                            }
 6846
 6847                            let range = Anchor {
 6848                                buffer_id: Some(buffer_id),
 6849                                excerpt_id,
 6850                                text_anchor: start,
 6851                                diff_base_anchor: None,
 6852                            }..Anchor {
 6853                                buffer_id: Some(buffer_id),
 6854                                excerpt_id,
 6855                                text_anchor: end,
 6856                                diff_base_anchor: None,
 6857                            };
 6858                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6859                                write_ranges.push(range);
 6860                            } else {
 6861                                read_ranges.push(range);
 6862                            }
 6863                        }
 6864                    }
 6865
 6866                    this.highlight_background::<DocumentHighlightRead>(
 6867                        &read_ranges,
 6868                        |theme| theme.colors().editor_document_highlight_read_background,
 6869                        cx,
 6870                    );
 6871                    this.highlight_background::<DocumentHighlightWrite>(
 6872                        &write_ranges,
 6873                        |theme| theme.colors().editor_document_highlight_write_background,
 6874                        cx,
 6875                    );
 6876                    cx.notify();
 6877                })
 6878                .log_err();
 6879            }
 6880        }));
 6881        None
 6882    }
 6883
 6884    fn prepare_highlight_query_from_selection(
 6885        &mut self,
 6886        cx: &mut Context<Editor>,
 6887    ) -> Option<(String, Range<Anchor>)> {
 6888        if matches!(self.mode, EditorMode::SingleLine) {
 6889            return None;
 6890        }
 6891        if !EditorSettings::get_global(cx).selection_highlight {
 6892            return None;
 6893        }
 6894        if self.selections.count() != 1 || self.selections.line_mode {
 6895            return None;
 6896        }
 6897        let selection = self.selections.newest::<Point>(cx);
 6898        if selection.is_empty() || selection.start.row != selection.end.row {
 6899            return None;
 6900        }
 6901        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6902        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6903        let query = multi_buffer_snapshot
 6904            .text_for_range(selection_anchor_range.clone())
 6905            .collect::<String>();
 6906        if query.trim().is_empty() {
 6907            return None;
 6908        }
 6909        Some((query, selection_anchor_range))
 6910    }
 6911
 6912    fn update_selection_occurrence_highlights(
 6913        &mut self,
 6914        query_text: String,
 6915        query_range: Range<Anchor>,
 6916        multi_buffer_range_to_query: Range<Point>,
 6917        use_debounce: bool,
 6918        window: &mut Window,
 6919        cx: &mut Context<Editor>,
 6920    ) -> Task<()> {
 6921        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6922        cx.spawn_in(window, async move |editor, cx| {
 6923            if use_debounce {
 6924                cx.background_executor()
 6925                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6926                    .await;
 6927            }
 6928            let match_task = cx.background_spawn(async move {
 6929                let buffer_ranges = multi_buffer_snapshot
 6930                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6931                    .into_iter()
 6932                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6933                let mut match_ranges = Vec::new();
 6934                let Ok(regex) = project::search::SearchQuery::text(
 6935                    query_text.clone(),
 6936                    false,
 6937                    false,
 6938                    false,
 6939                    Default::default(),
 6940                    Default::default(),
 6941                    false,
 6942                    None,
 6943                ) else {
 6944                    return Vec::default();
 6945                };
 6946                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6947                    match_ranges.extend(
 6948                        regex
 6949                            .search(buffer_snapshot, Some(search_range.clone()))
 6950                            .await
 6951                            .into_iter()
 6952                            .filter_map(|match_range| {
 6953                                let match_start = buffer_snapshot
 6954                                    .anchor_after(search_range.start + match_range.start);
 6955                                let match_end = buffer_snapshot
 6956                                    .anchor_before(search_range.start + match_range.end);
 6957                                let match_anchor_range = Anchor::range_in_buffer(
 6958                                    excerpt_id,
 6959                                    buffer_snapshot.remote_id(),
 6960                                    match_start..match_end,
 6961                                );
 6962                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6963                            }),
 6964                    );
 6965                }
 6966                match_ranges
 6967            });
 6968            let match_ranges = match_task.await;
 6969            editor
 6970                .update_in(cx, |editor, _, cx| {
 6971                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6972                    if !match_ranges.is_empty() {
 6973                        editor.highlight_background::<SelectedTextHighlight>(
 6974                            &match_ranges,
 6975                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6976                            cx,
 6977                        )
 6978                    }
 6979                })
 6980                .log_err();
 6981        })
 6982    }
 6983
 6984    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6985        struct NewlineFold;
 6986        let type_id = std::any::TypeId::of::<NewlineFold>();
 6987        if !self.mode.is_single_line() {
 6988            return;
 6989        }
 6990        let snapshot = self.snapshot(window, cx);
 6991        if snapshot.buffer_snapshot.max_point().row == 0 {
 6992            return;
 6993        }
 6994        let task = cx.background_spawn(async move {
 6995            let new_newlines = snapshot
 6996                .buffer_chars_at(0)
 6997                .filter_map(|(c, i)| {
 6998                    if c == '\n' {
 6999                        Some(
 7000                            snapshot.buffer_snapshot.anchor_after(i)
 7001                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7002                        )
 7003                    } else {
 7004                        None
 7005                    }
 7006                })
 7007                .collect::<Vec<_>>();
 7008            let existing_newlines = snapshot
 7009                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7010                .filter_map(|fold| {
 7011                    if fold.placeholder.type_tag == Some(type_id) {
 7012                        Some(fold.range.start..fold.range.end)
 7013                    } else {
 7014                        None
 7015                    }
 7016                })
 7017                .collect::<Vec<_>>();
 7018
 7019            (new_newlines, existing_newlines)
 7020        });
 7021        self.folding_newlines = cx.spawn(async move |this, cx| {
 7022            let (new_newlines, existing_newlines) = task.await;
 7023            if new_newlines == existing_newlines {
 7024                return;
 7025            }
 7026            let placeholder = FoldPlaceholder {
 7027                render: Arc::new(move |_, _, cx| {
 7028                    div()
 7029                        .bg(cx.theme().status().hint_background)
 7030                        .border_b_1()
 7031                        .size_full()
 7032                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7033                        .border_color(cx.theme().status().hint)
 7034                        .child("\\n")
 7035                        .into_any()
 7036                }),
 7037                constrain_width: false,
 7038                merge_adjacent: false,
 7039                type_tag: Some(type_id),
 7040            };
 7041            let creases = new_newlines
 7042                .into_iter()
 7043                .map(|range| Crease::simple(range, placeholder.clone()))
 7044                .collect();
 7045            this.update(cx, |this, cx| {
 7046                this.display_map.update(cx, |display_map, cx| {
 7047                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7048                    display_map.fold(creases, cx);
 7049                });
 7050            })
 7051            .ok();
 7052        });
 7053    }
 7054
 7055    fn refresh_selected_text_highlights(
 7056        &mut self,
 7057        on_buffer_edit: bool,
 7058        window: &mut Window,
 7059        cx: &mut Context<Editor>,
 7060    ) {
 7061        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7062        else {
 7063            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7064            self.quick_selection_highlight_task.take();
 7065            self.debounced_selection_highlight_task.take();
 7066            return;
 7067        };
 7068        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7069        if on_buffer_edit
 7070            || self
 7071                .quick_selection_highlight_task
 7072                .as_ref()
 7073                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7074        {
 7075            let multi_buffer_visible_start = self
 7076                .scroll_manager
 7077                .anchor()
 7078                .anchor
 7079                .to_point(&multi_buffer_snapshot);
 7080            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7081                multi_buffer_visible_start
 7082                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7083                Bias::Left,
 7084            );
 7085            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7086            self.quick_selection_highlight_task = Some((
 7087                query_range.clone(),
 7088                self.update_selection_occurrence_highlights(
 7089                    query_text.clone(),
 7090                    query_range.clone(),
 7091                    multi_buffer_visible_range,
 7092                    false,
 7093                    window,
 7094                    cx,
 7095                ),
 7096            ));
 7097        }
 7098        if on_buffer_edit
 7099            || self
 7100                .debounced_selection_highlight_task
 7101                .as_ref()
 7102                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7103        {
 7104            let multi_buffer_start = multi_buffer_snapshot
 7105                .anchor_before(0)
 7106                .to_point(&multi_buffer_snapshot);
 7107            let multi_buffer_end = multi_buffer_snapshot
 7108                .anchor_after(multi_buffer_snapshot.len())
 7109                .to_point(&multi_buffer_snapshot);
 7110            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7111            self.debounced_selection_highlight_task = Some((
 7112                query_range.clone(),
 7113                self.update_selection_occurrence_highlights(
 7114                    query_text,
 7115                    query_range,
 7116                    multi_buffer_full_range,
 7117                    true,
 7118                    window,
 7119                    cx,
 7120                ),
 7121            ));
 7122        }
 7123    }
 7124
 7125    pub fn refresh_edit_prediction(
 7126        &mut self,
 7127        debounce: bool,
 7128        user_requested: bool,
 7129        window: &mut Window,
 7130        cx: &mut Context<Self>,
 7131    ) -> Option<()> {
 7132        if DisableAiSettings::get_global(cx).disable_ai {
 7133            return None;
 7134        }
 7135
 7136        let provider = self.edit_prediction_provider()?;
 7137        let cursor = self.selections.newest_anchor().head();
 7138        let (buffer, cursor_buffer_position) =
 7139            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7140
 7141        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7142            self.discard_edit_prediction(false, cx);
 7143            return None;
 7144        }
 7145
 7146        if !user_requested
 7147            && (!self.should_show_edit_predictions()
 7148                || !self.is_focused(window)
 7149                || buffer.read(cx).is_empty())
 7150        {
 7151            self.discard_edit_prediction(false, cx);
 7152            return None;
 7153        }
 7154
 7155        self.update_visible_edit_prediction(window, cx);
 7156        provider.refresh(
 7157            self.project.clone(),
 7158            buffer,
 7159            cursor_buffer_position,
 7160            debounce,
 7161            cx,
 7162        );
 7163        Some(())
 7164    }
 7165
 7166    fn show_edit_predictions_in_menu(&self) -> bool {
 7167        match self.edit_prediction_settings {
 7168            EditPredictionSettings::Disabled => false,
 7169            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7170        }
 7171    }
 7172
 7173    pub fn edit_predictions_enabled(&self) -> bool {
 7174        match self.edit_prediction_settings {
 7175            EditPredictionSettings::Disabled => false,
 7176            EditPredictionSettings::Enabled { .. } => true,
 7177        }
 7178    }
 7179
 7180    fn edit_prediction_requires_modifier(&self) -> bool {
 7181        match self.edit_prediction_settings {
 7182            EditPredictionSettings::Disabled => false,
 7183            EditPredictionSettings::Enabled {
 7184                preview_requires_modifier,
 7185                ..
 7186            } => preview_requires_modifier,
 7187        }
 7188    }
 7189
 7190    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7191        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7192            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7193            self.discard_edit_prediction(false, cx);
 7194        } else {
 7195            let selection = self.selections.newest_anchor();
 7196            let cursor = selection.head();
 7197
 7198            if let Some((buffer, cursor_buffer_position)) =
 7199                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7200            {
 7201                self.edit_prediction_settings =
 7202                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7203            }
 7204        }
 7205    }
 7206
 7207    fn edit_prediction_settings_at_position(
 7208        &self,
 7209        buffer: &Entity<Buffer>,
 7210        buffer_position: language::Anchor,
 7211        cx: &App,
 7212    ) -> EditPredictionSettings {
 7213        if !self.mode.is_full()
 7214            || !self.show_edit_predictions_override.unwrap_or(true)
 7215            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7216        {
 7217            return EditPredictionSettings::Disabled;
 7218        }
 7219
 7220        let buffer = buffer.read(cx);
 7221
 7222        let file = buffer.file();
 7223
 7224        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7225            return EditPredictionSettings::Disabled;
 7226        };
 7227
 7228        let by_provider = matches!(
 7229            self.menu_edit_predictions_policy,
 7230            MenuEditPredictionsPolicy::ByProvider
 7231        );
 7232
 7233        let show_in_menu = by_provider
 7234            && self
 7235                .edit_prediction_provider
 7236                .as_ref()
 7237                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7238
 7239        let preview_requires_modifier =
 7240            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7241
 7242        EditPredictionSettings::Enabled {
 7243            show_in_menu,
 7244            preview_requires_modifier,
 7245        }
 7246    }
 7247
 7248    fn should_show_edit_predictions(&self) -> bool {
 7249        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7250    }
 7251
 7252    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7253        matches!(
 7254            self.edit_prediction_preview,
 7255            EditPredictionPreview::Active { .. }
 7256        )
 7257    }
 7258
 7259    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7260        let cursor = self.selections.newest_anchor().head();
 7261        if let Some((buffer, cursor_position)) =
 7262            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7263        {
 7264            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7265        } else {
 7266            false
 7267        }
 7268    }
 7269
 7270    pub fn supports_minimap(&self, cx: &App) -> bool {
 7271        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7272    }
 7273
 7274    fn edit_predictions_enabled_in_buffer(
 7275        &self,
 7276        buffer: &Entity<Buffer>,
 7277        buffer_position: language::Anchor,
 7278        cx: &App,
 7279    ) -> bool {
 7280        maybe!({
 7281            if self.read_only(cx) {
 7282                return Some(false);
 7283            }
 7284            let provider = self.edit_prediction_provider()?;
 7285            if !provider.is_enabled(buffer, buffer_position, cx) {
 7286                return Some(false);
 7287            }
 7288            let buffer = buffer.read(cx);
 7289            let Some(file) = buffer.file() else {
 7290                return Some(true);
 7291            };
 7292            let settings = all_language_settings(Some(file), cx);
 7293            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7294        })
 7295        .unwrap_or(false)
 7296    }
 7297
 7298    fn cycle_edit_prediction(
 7299        &mut self,
 7300        direction: Direction,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) -> Option<()> {
 7304        let provider = self.edit_prediction_provider()?;
 7305        let cursor = self.selections.newest_anchor().head();
 7306        let (buffer, cursor_buffer_position) =
 7307            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7308        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7309            return None;
 7310        }
 7311
 7312        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7313        self.update_visible_edit_prediction(window, cx);
 7314
 7315        Some(())
 7316    }
 7317
 7318    pub fn show_edit_prediction(
 7319        &mut self,
 7320        _: &ShowEditPrediction,
 7321        window: &mut Window,
 7322        cx: &mut Context<Self>,
 7323    ) {
 7324        if !self.has_active_edit_prediction() {
 7325            self.refresh_edit_prediction(false, true, window, cx);
 7326            return;
 7327        }
 7328
 7329        self.update_visible_edit_prediction(window, cx);
 7330    }
 7331
 7332    pub fn display_cursor_names(
 7333        &mut self,
 7334        _: &DisplayCursorNames,
 7335        window: &mut Window,
 7336        cx: &mut Context<Self>,
 7337    ) {
 7338        self.show_cursor_names(window, cx);
 7339    }
 7340
 7341    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7342        self.show_cursor_names = true;
 7343        cx.notify();
 7344        cx.spawn_in(window, async move |this, cx| {
 7345            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7346            this.update(cx, |this, cx| {
 7347                this.show_cursor_names = false;
 7348                cx.notify()
 7349            })
 7350            .ok()
 7351        })
 7352        .detach();
 7353    }
 7354
 7355    pub fn next_edit_prediction(
 7356        &mut self,
 7357        _: &NextEditPrediction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) {
 7361        if self.has_active_edit_prediction() {
 7362            self.cycle_edit_prediction(Direction::Next, window, cx);
 7363        } else {
 7364            let is_copilot_disabled = self
 7365                .refresh_edit_prediction(false, true, window, cx)
 7366                .is_none();
 7367            if is_copilot_disabled {
 7368                cx.propagate();
 7369            }
 7370        }
 7371    }
 7372
 7373    pub fn previous_edit_prediction(
 7374        &mut self,
 7375        _: &PreviousEditPrediction,
 7376        window: &mut Window,
 7377        cx: &mut Context<Self>,
 7378    ) {
 7379        if self.has_active_edit_prediction() {
 7380            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7381        } else {
 7382            let is_copilot_disabled = self
 7383                .refresh_edit_prediction(false, true, window, cx)
 7384                .is_none();
 7385            if is_copilot_disabled {
 7386                cx.propagate();
 7387            }
 7388        }
 7389    }
 7390
 7391    pub fn accept_edit_prediction(
 7392        &mut self,
 7393        _: &AcceptEditPrediction,
 7394        window: &mut Window,
 7395        cx: &mut Context<Self>,
 7396    ) {
 7397        if self.show_edit_predictions_in_menu() {
 7398            self.hide_context_menu(window, cx);
 7399        }
 7400
 7401        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7402            return;
 7403        };
 7404
 7405        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7406
 7407        match &active_edit_prediction.completion {
 7408            EditPrediction::Move { target, .. } => {
 7409                let target = *target;
 7410
 7411                if let Some(position_map) = &self.last_position_map {
 7412                    if position_map
 7413                        .visible_row_range
 7414                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7415                        || !self.edit_prediction_requires_modifier()
 7416                    {
 7417                        self.unfold_ranges(&[target..target], true, false, cx);
 7418                        // Note that this is also done in vim's handler of the Tab action.
 7419                        self.change_selections(
 7420                            SelectionEffects::scroll(Autoscroll::newest()),
 7421                            window,
 7422                            cx,
 7423                            |selections| {
 7424                                selections.select_anchor_ranges([target..target]);
 7425                            },
 7426                        );
 7427                        self.clear_row_highlights::<EditPredictionPreview>();
 7428
 7429                        self.edit_prediction_preview
 7430                            .set_previous_scroll_position(None);
 7431                    } else {
 7432                        self.edit_prediction_preview
 7433                            .set_previous_scroll_position(Some(
 7434                                position_map.snapshot.scroll_anchor,
 7435                            ));
 7436
 7437                        self.highlight_rows::<EditPredictionPreview>(
 7438                            target..target,
 7439                            cx.theme().colors().editor_highlighted_line_background,
 7440                            RowHighlightOptions {
 7441                                autoscroll: true,
 7442                                ..Default::default()
 7443                            },
 7444                            cx,
 7445                        );
 7446                        self.request_autoscroll(Autoscroll::fit(), cx);
 7447                    }
 7448                }
 7449            }
 7450            EditPrediction::Edit { edits, .. } => {
 7451                if let Some(provider) = self.edit_prediction_provider() {
 7452                    provider.accept(cx);
 7453                }
 7454
 7455                // Store the transaction ID and selections before applying the edit
 7456                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7457
 7458                let snapshot = self.buffer.read(cx).snapshot(cx);
 7459                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7460
 7461                self.buffer.update(cx, |buffer, cx| {
 7462                    buffer.edit(edits.iter().cloned(), None, cx)
 7463                });
 7464
 7465                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7466                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7467                });
 7468
 7469                let selections = self.selections.disjoint_anchors();
 7470                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7471                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7472                    if has_new_transaction {
 7473                        self.selection_history
 7474                            .insert_transaction(transaction_id_now, selections);
 7475                    }
 7476                }
 7477
 7478                self.update_visible_edit_prediction(window, cx);
 7479                if self.active_edit_prediction.is_none() {
 7480                    self.refresh_edit_prediction(true, true, window, cx);
 7481                }
 7482
 7483                cx.notify();
 7484            }
 7485        }
 7486
 7487        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7488    }
 7489
 7490    pub fn accept_partial_edit_prediction(
 7491        &mut self,
 7492        _: &AcceptPartialEditPrediction,
 7493        window: &mut Window,
 7494        cx: &mut Context<Self>,
 7495    ) {
 7496        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7497            return;
 7498        };
 7499        if self.selections.count() != 1 {
 7500            return;
 7501        }
 7502
 7503        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7504
 7505        match &active_edit_prediction.completion {
 7506            EditPrediction::Move { target, .. } => {
 7507                let target = *target;
 7508                self.change_selections(
 7509                    SelectionEffects::scroll(Autoscroll::newest()),
 7510                    window,
 7511                    cx,
 7512                    |selections| {
 7513                        selections.select_anchor_ranges([target..target]);
 7514                    },
 7515                );
 7516            }
 7517            EditPrediction::Edit { edits, .. } => {
 7518                // Find an insertion that starts at the cursor position.
 7519                let snapshot = self.buffer.read(cx).snapshot(cx);
 7520                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7521                let insertion = edits.iter().find_map(|(range, text)| {
 7522                    let range = range.to_offset(&snapshot);
 7523                    if range.is_empty() && range.start == cursor_offset {
 7524                        Some(text)
 7525                    } else {
 7526                        None
 7527                    }
 7528                });
 7529
 7530                if let Some(text) = insertion {
 7531                    let mut partial_completion = text
 7532                        .chars()
 7533                        .by_ref()
 7534                        .take_while(|c| c.is_alphabetic())
 7535                        .collect::<String>();
 7536                    if partial_completion.is_empty() {
 7537                        partial_completion = text
 7538                            .chars()
 7539                            .by_ref()
 7540                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7541                            .collect::<String>();
 7542                    }
 7543
 7544                    cx.emit(EditorEvent::InputHandled {
 7545                        utf16_range_to_replace: None,
 7546                        text: partial_completion.clone().into(),
 7547                    });
 7548
 7549                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7550
 7551                    self.refresh_edit_prediction(true, true, window, cx);
 7552                    cx.notify();
 7553                } else {
 7554                    self.accept_edit_prediction(&Default::default(), window, cx);
 7555                }
 7556            }
 7557        }
 7558    }
 7559
 7560    fn discard_edit_prediction(
 7561        &mut self,
 7562        should_report_edit_prediction_event: bool,
 7563        cx: &mut Context<Self>,
 7564    ) -> bool {
 7565        if should_report_edit_prediction_event {
 7566            let completion_id = self
 7567                .active_edit_prediction
 7568                .as_ref()
 7569                .and_then(|active_completion| active_completion.completion_id.clone());
 7570
 7571            self.report_edit_prediction_event(completion_id, false, cx);
 7572        }
 7573
 7574        if let Some(provider) = self.edit_prediction_provider() {
 7575            provider.discard(cx);
 7576        }
 7577
 7578        self.take_active_edit_prediction(cx)
 7579    }
 7580
 7581    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7582        let Some(provider) = self.edit_prediction_provider() else {
 7583            return;
 7584        };
 7585
 7586        let Some((_, buffer, _)) = self
 7587            .buffer
 7588            .read(cx)
 7589            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7590        else {
 7591            return;
 7592        };
 7593
 7594        let extension = buffer
 7595            .read(cx)
 7596            .file()
 7597            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7598
 7599        let event_type = match accepted {
 7600            true => "Edit Prediction Accepted",
 7601            false => "Edit Prediction Discarded",
 7602        };
 7603        telemetry::event!(
 7604            event_type,
 7605            provider = provider.name(),
 7606            prediction_id = id,
 7607            suggestion_accepted = accepted,
 7608            file_extension = extension,
 7609        );
 7610    }
 7611
 7612    pub fn has_active_edit_prediction(&self) -> bool {
 7613        self.active_edit_prediction.is_some()
 7614    }
 7615
 7616    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7617        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7618            return false;
 7619        };
 7620
 7621        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7622        self.clear_highlights::<EditPredictionHighlight>(cx);
 7623        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7624        true
 7625    }
 7626
 7627    /// Returns true when we're displaying the edit prediction popover below the cursor
 7628    /// like we are not previewing and the LSP autocomplete menu is visible
 7629    /// or we are in `when_holding_modifier` mode.
 7630    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7631        if self.edit_prediction_preview_is_active()
 7632            || !self.show_edit_predictions_in_menu()
 7633            || !self.edit_predictions_enabled()
 7634        {
 7635            return false;
 7636        }
 7637
 7638        if self.has_visible_completions_menu() {
 7639            return true;
 7640        }
 7641
 7642        has_completion && self.edit_prediction_requires_modifier()
 7643    }
 7644
 7645    fn handle_modifiers_changed(
 7646        &mut self,
 7647        modifiers: Modifiers,
 7648        position_map: &PositionMap,
 7649        window: &mut Window,
 7650        cx: &mut Context<Self>,
 7651    ) {
 7652        if self.show_edit_predictions_in_menu() {
 7653            self.update_edit_prediction_preview(&modifiers, window, cx);
 7654        }
 7655
 7656        self.update_selection_mode(&modifiers, position_map, window, cx);
 7657
 7658        let mouse_position = window.mouse_position();
 7659        if !position_map.text_hitbox.is_hovered(window) {
 7660            return;
 7661        }
 7662
 7663        self.update_hovered_link(
 7664            position_map.point_for_position(mouse_position),
 7665            &position_map.snapshot,
 7666            modifiers,
 7667            window,
 7668            cx,
 7669        )
 7670    }
 7671
 7672    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7673        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7674        if invert {
 7675            match multi_cursor_setting {
 7676                MultiCursorModifier::Alt => modifiers.alt,
 7677                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7678            }
 7679        } else {
 7680            match multi_cursor_setting {
 7681                MultiCursorModifier::Alt => modifiers.secondary(),
 7682                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7683            }
 7684        }
 7685    }
 7686
 7687    fn columnar_selection_mode(
 7688        modifiers: &Modifiers,
 7689        cx: &mut Context<Self>,
 7690    ) -> Option<ColumnarMode> {
 7691        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7692            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7693                Some(ColumnarMode::FromMouse)
 7694            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7695                Some(ColumnarMode::FromSelection)
 7696            } else {
 7697                None
 7698            }
 7699        } else {
 7700            None
 7701        }
 7702    }
 7703
 7704    fn update_selection_mode(
 7705        &mut self,
 7706        modifiers: &Modifiers,
 7707        position_map: &PositionMap,
 7708        window: &mut Window,
 7709        cx: &mut Context<Self>,
 7710    ) {
 7711        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7712            return;
 7713        };
 7714        if self.selections.pending.is_none() {
 7715            return;
 7716        }
 7717
 7718        let mouse_position = window.mouse_position();
 7719        let point_for_position = position_map.point_for_position(mouse_position);
 7720        let position = point_for_position.previous_valid;
 7721
 7722        self.select(
 7723            SelectPhase::BeginColumnar {
 7724                position,
 7725                reset: false,
 7726                mode,
 7727                goal_column: point_for_position.exact_unclipped.column(),
 7728            },
 7729            window,
 7730            cx,
 7731        );
 7732    }
 7733
 7734    fn update_edit_prediction_preview(
 7735        &mut self,
 7736        modifiers: &Modifiers,
 7737        window: &mut Window,
 7738        cx: &mut Context<Self>,
 7739    ) {
 7740        let mut modifiers_held = false;
 7741        if let Some(accept_keystroke) = self
 7742            .accept_edit_prediction_keybind(false, window, cx)
 7743            .keystroke()
 7744        {
 7745            modifiers_held = modifiers_held
 7746                || (accept_keystroke.modifiers() == modifiers
 7747                    && accept_keystroke.modifiers().modified());
 7748        };
 7749        if let Some(accept_partial_keystroke) = self
 7750            .accept_edit_prediction_keybind(true, window, cx)
 7751            .keystroke()
 7752        {
 7753            modifiers_held = modifiers_held
 7754                || (accept_partial_keystroke.modifiers() == modifiers
 7755                    && accept_partial_keystroke.modifiers().modified());
 7756        }
 7757
 7758        if modifiers_held {
 7759            if matches!(
 7760                self.edit_prediction_preview,
 7761                EditPredictionPreview::Inactive { .. }
 7762            ) {
 7763                self.edit_prediction_preview = EditPredictionPreview::Active {
 7764                    previous_scroll_position: None,
 7765                    since: Instant::now(),
 7766                };
 7767
 7768                self.update_visible_edit_prediction(window, cx);
 7769                cx.notify();
 7770            }
 7771        } else if let EditPredictionPreview::Active {
 7772            previous_scroll_position,
 7773            since,
 7774        } = self.edit_prediction_preview
 7775        {
 7776            if let (Some(previous_scroll_position), Some(position_map)) =
 7777                (previous_scroll_position, self.last_position_map.as_ref())
 7778            {
 7779                self.set_scroll_position(
 7780                    previous_scroll_position
 7781                        .scroll_position(&position_map.snapshot.display_snapshot),
 7782                    window,
 7783                    cx,
 7784                );
 7785            }
 7786
 7787            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7788                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7789            };
 7790            self.clear_row_highlights::<EditPredictionPreview>();
 7791            self.update_visible_edit_prediction(window, cx);
 7792            cx.notify();
 7793        }
 7794    }
 7795
 7796    fn update_visible_edit_prediction(
 7797        &mut self,
 7798        _window: &mut Window,
 7799        cx: &mut Context<Self>,
 7800    ) -> Option<()> {
 7801        if DisableAiSettings::get_global(cx).disable_ai {
 7802            return None;
 7803        }
 7804
 7805        if self.ime_transaction.is_some() {
 7806            self.discard_edit_prediction(false, cx);
 7807            return None;
 7808        }
 7809
 7810        let selection = self.selections.newest_anchor();
 7811        let cursor = selection.head();
 7812        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7813        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7814        let excerpt_id = cursor.excerpt_id;
 7815
 7816        let show_in_menu = self.show_edit_predictions_in_menu();
 7817        let completions_menu_has_precedence = !show_in_menu
 7818            && (self.context_menu.borrow().is_some()
 7819                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7820
 7821        if completions_menu_has_precedence
 7822            || !offset_selection.is_empty()
 7823            || self
 7824                .active_edit_prediction
 7825                .as_ref()
 7826                .is_some_and(|completion| {
 7827                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7828                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7829                    !invalidation_range.contains(&offset_selection.head())
 7830                })
 7831        {
 7832            self.discard_edit_prediction(false, cx);
 7833            return None;
 7834        }
 7835
 7836        self.take_active_edit_prediction(cx);
 7837        let Some(provider) = self.edit_prediction_provider() else {
 7838            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7839            return None;
 7840        };
 7841
 7842        let (buffer, cursor_buffer_position) =
 7843            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7844
 7845        self.edit_prediction_settings =
 7846            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7847
 7848        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7849            self.discard_edit_prediction(false, cx);
 7850            return None;
 7851        };
 7852
 7853        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7854
 7855        if self.edit_prediction_indent_conflict {
 7856            let cursor_point = cursor.to_point(&multibuffer);
 7857
 7858            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7859
 7860            if let Some((_, indent)) = indents.iter().next()
 7861                && indent.len == cursor_point.column
 7862            {
 7863                self.edit_prediction_indent_conflict = false;
 7864            }
 7865        }
 7866
 7867        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7868        let edits = edit_prediction
 7869            .edits
 7870            .into_iter()
 7871            .flat_map(|(range, new_text)| {
 7872                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7873                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7874                Some((start..end, new_text))
 7875            })
 7876            .collect::<Vec<_>>();
 7877        if edits.is_empty() {
 7878            return None;
 7879        }
 7880
 7881        let first_edit_start = edits.first().unwrap().0.start;
 7882        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7883        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7884
 7885        let last_edit_end = edits.last().unwrap().0.end;
 7886        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7887        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7888
 7889        let cursor_row = cursor.to_point(&multibuffer).row;
 7890
 7891        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7892
 7893        let mut inlay_ids = Vec::new();
 7894        let invalidation_row_range;
 7895        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7896            Some(cursor_row..edit_end_row)
 7897        } else if cursor_row > edit_end_row {
 7898            Some(edit_start_row..cursor_row)
 7899        } else {
 7900            None
 7901        };
 7902        let supports_jump = self
 7903            .edit_prediction_provider
 7904            .as_ref()
 7905            .map(|provider| provider.provider.supports_jump_to_edit())
 7906            .unwrap_or(true);
 7907
 7908        let is_move = supports_jump
 7909            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7910        let completion = if is_move {
 7911            invalidation_row_range =
 7912                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7913            let target = first_edit_start;
 7914            EditPrediction::Move { target, snapshot }
 7915        } else {
 7916            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7917                && !self.edit_predictions_hidden_for_vim_mode;
 7918
 7919            if show_completions_in_buffer {
 7920                if edits
 7921                    .iter()
 7922                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7923                {
 7924                    let mut inlays = Vec::new();
 7925                    for (range, new_text) in &edits {
 7926                        let inlay = Inlay::edit_prediction(
 7927                            post_inc(&mut self.next_inlay_id),
 7928                            range.start,
 7929                            new_text.as_str(),
 7930                        );
 7931                        inlay_ids.push(inlay.id);
 7932                        inlays.push(inlay);
 7933                    }
 7934
 7935                    self.splice_inlays(&[], inlays, cx);
 7936                } else {
 7937                    let background_color = cx.theme().status().deleted_background;
 7938                    self.highlight_text::<EditPredictionHighlight>(
 7939                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7940                        HighlightStyle {
 7941                            background_color: Some(background_color),
 7942                            ..Default::default()
 7943                        },
 7944                        cx,
 7945                    );
 7946                }
 7947            }
 7948
 7949            invalidation_row_range = edit_start_row..edit_end_row;
 7950
 7951            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7952                if provider.show_tab_accept_marker() {
 7953                    EditDisplayMode::TabAccept
 7954                } else {
 7955                    EditDisplayMode::Inline
 7956                }
 7957            } else {
 7958                EditDisplayMode::DiffPopover
 7959            };
 7960
 7961            EditPrediction::Edit {
 7962                edits,
 7963                edit_preview: edit_prediction.edit_preview,
 7964                display_mode,
 7965                snapshot,
 7966            }
 7967        };
 7968
 7969        let invalidation_range = multibuffer
 7970            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7971            ..multibuffer.anchor_after(Point::new(
 7972                invalidation_row_range.end,
 7973                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7974            ));
 7975
 7976        self.stale_edit_prediction_in_menu = None;
 7977        self.active_edit_prediction = Some(EditPredictionState {
 7978            inlay_ids,
 7979            completion,
 7980            completion_id: edit_prediction.id,
 7981            invalidation_range,
 7982        });
 7983
 7984        cx.notify();
 7985
 7986        Some(())
 7987    }
 7988
 7989    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7990        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7991    }
 7992
 7993    fn clear_tasks(&mut self) {
 7994        self.tasks.clear()
 7995    }
 7996
 7997    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7998        if self.tasks.insert(key, value).is_some() {
 7999            // This case should hopefully be rare, but just in case...
 8000            log::error!(
 8001                "multiple different run targets found on a single line, only the last target will be rendered"
 8002            )
 8003        }
 8004    }
 8005
 8006    /// Get all display points of breakpoints that will be rendered within editor
 8007    ///
 8008    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8009    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8010    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8011    fn active_breakpoints(
 8012        &self,
 8013        range: Range<DisplayRow>,
 8014        window: &mut Window,
 8015        cx: &mut Context<Self>,
 8016    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8017        let mut breakpoint_display_points = HashMap::default();
 8018
 8019        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8020            return breakpoint_display_points;
 8021        };
 8022
 8023        let snapshot = self.snapshot(window, cx);
 8024
 8025        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8026        let Some(project) = self.project() else {
 8027            return breakpoint_display_points;
 8028        };
 8029
 8030        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8031            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8032
 8033        for (buffer_snapshot, range, excerpt_id) in
 8034            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8035        {
 8036            let Some(buffer) = project
 8037                .read(cx)
 8038                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8039            else {
 8040                continue;
 8041            };
 8042            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8043                &buffer,
 8044                Some(
 8045                    buffer_snapshot.anchor_before(range.start)
 8046                        ..buffer_snapshot.anchor_after(range.end),
 8047                ),
 8048                buffer_snapshot,
 8049                cx,
 8050            );
 8051            for (breakpoint, state) in breakpoints {
 8052                let multi_buffer_anchor =
 8053                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8054                let position = multi_buffer_anchor
 8055                    .to_point(multi_buffer_snapshot)
 8056                    .to_display_point(&snapshot);
 8057
 8058                breakpoint_display_points.insert(
 8059                    position.row(),
 8060                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8061                );
 8062            }
 8063        }
 8064
 8065        breakpoint_display_points
 8066    }
 8067
 8068    fn breakpoint_context_menu(
 8069        &self,
 8070        anchor: Anchor,
 8071        window: &mut Window,
 8072        cx: &mut Context<Self>,
 8073    ) -> Entity<ui::ContextMenu> {
 8074        let weak_editor = cx.weak_entity();
 8075        let focus_handle = self.focus_handle(cx);
 8076
 8077        let row = self
 8078            .buffer
 8079            .read(cx)
 8080            .snapshot(cx)
 8081            .summary_for_anchor::<Point>(&anchor)
 8082            .row;
 8083
 8084        let breakpoint = self
 8085            .breakpoint_at_row(row, window, cx)
 8086            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8087
 8088        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8089            "Edit Log Breakpoint"
 8090        } else {
 8091            "Set Log Breakpoint"
 8092        };
 8093
 8094        let condition_breakpoint_msg = if breakpoint
 8095            .as_ref()
 8096            .is_some_and(|bp| bp.1.condition.is_some())
 8097        {
 8098            "Edit Condition Breakpoint"
 8099        } else {
 8100            "Set Condition Breakpoint"
 8101        };
 8102
 8103        let hit_condition_breakpoint_msg = if breakpoint
 8104            .as_ref()
 8105            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8106        {
 8107            "Edit Hit Condition Breakpoint"
 8108        } else {
 8109            "Set Hit Condition Breakpoint"
 8110        };
 8111
 8112        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8113            "Unset Breakpoint"
 8114        } else {
 8115            "Set Breakpoint"
 8116        };
 8117
 8118        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8119
 8120        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8121            BreakpointState::Enabled => Some("Disable"),
 8122            BreakpointState::Disabled => Some("Enable"),
 8123        });
 8124
 8125        let (anchor, breakpoint) =
 8126            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8127
 8128        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8129            menu.on_blur_subscription(Subscription::new(|| {}))
 8130                .context(focus_handle)
 8131                .when(run_to_cursor, |this| {
 8132                    let weak_editor = weak_editor.clone();
 8133                    this.entry("Run to cursor", None, move |window, cx| {
 8134                        weak_editor
 8135                            .update(cx, |editor, cx| {
 8136                                editor.change_selections(
 8137                                    SelectionEffects::no_scroll(),
 8138                                    window,
 8139                                    cx,
 8140                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8141                                );
 8142                            })
 8143                            .ok();
 8144
 8145                        window.dispatch_action(Box::new(RunToCursor), cx);
 8146                    })
 8147                    .separator()
 8148                })
 8149                .when_some(toggle_state_msg, |this, msg| {
 8150                    this.entry(msg, None, {
 8151                        let weak_editor = weak_editor.clone();
 8152                        let breakpoint = breakpoint.clone();
 8153                        move |_window, cx| {
 8154                            weak_editor
 8155                                .update(cx, |this, cx| {
 8156                                    this.edit_breakpoint_at_anchor(
 8157                                        anchor,
 8158                                        breakpoint.as_ref().clone(),
 8159                                        BreakpointEditAction::InvertState,
 8160                                        cx,
 8161                                    );
 8162                                })
 8163                                .log_err();
 8164                        }
 8165                    })
 8166                })
 8167                .entry(set_breakpoint_msg, None, {
 8168                    let weak_editor = weak_editor.clone();
 8169                    let breakpoint = breakpoint.clone();
 8170                    move |_window, cx| {
 8171                        weak_editor
 8172                            .update(cx, |this, cx| {
 8173                                this.edit_breakpoint_at_anchor(
 8174                                    anchor,
 8175                                    breakpoint.as_ref().clone(),
 8176                                    BreakpointEditAction::Toggle,
 8177                                    cx,
 8178                                );
 8179                            })
 8180                            .log_err();
 8181                    }
 8182                })
 8183                .entry(log_breakpoint_msg, None, {
 8184                    let breakpoint = breakpoint.clone();
 8185                    let weak_editor = weak_editor.clone();
 8186                    move |window, cx| {
 8187                        weak_editor
 8188                            .update(cx, |this, cx| {
 8189                                this.add_edit_breakpoint_block(
 8190                                    anchor,
 8191                                    breakpoint.as_ref(),
 8192                                    BreakpointPromptEditAction::Log,
 8193                                    window,
 8194                                    cx,
 8195                                );
 8196                            })
 8197                            .log_err();
 8198                    }
 8199                })
 8200                .entry(condition_breakpoint_msg, None, {
 8201                    let breakpoint = breakpoint.clone();
 8202                    let weak_editor = weak_editor.clone();
 8203                    move |window, cx| {
 8204                        weak_editor
 8205                            .update(cx, |this, cx| {
 8206                                this.add_edit_breakpoint_block(
 8207                                    anchor,
 8208                                    breakpoint.as_ref(),
 8209                                    BreakpointPromptEditAction::Condition,
 8210                                    window,
 8211                                    cx,
 8212                                );
 8213                            })
 8214                            .log_err();
 8215                    }
 8216                })
 8217                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8218                    weak_editor
 8219                        .update(cx, |this, cx| {
 8220                            this.add_edit_breakpoint_block(
 8221                                anchor,
 8222                                breakpoint.as_ref(),
 8223                                BreakpointPromptEditAction::HitCondition,
 8224                                window,
 8225                                cx,
 8226                            );
 8227                        })
 8228                        .log_err();
 8229                })
 8230        })
 8231    }
 8232
 8233    fn render_breakpoint(
 8234        &self,
 8235        position: Anchor,
 8236        row: DisplayRow,
 8237        breakpoint: &Breakpoint,
 8238        state: Option<BreakpointSessionState>,
 8239        cx: &mut Context<Self>,
 8240    ) -> IconButton {
 8241        let is_rejected = state.is_some_and(|s| !s.verified);
 8242        // Is it a breakpoint that shows up when hovering over gutter?
 8243        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8244            (false, false),
 8245            |PhantomBreakpointIndicator {
 8246                 is_active,
 8247                 display_row,
 8248                 collides_with_existing_breakpoint,
 8249             }| {
 8250                (
 8251                    is_active && display_row == row,
 8252                    collides_with_existing_breakpoint,
 8253                )
 8254            },
 8255        );
 8256
 8257        let (color, icon) = {
 8258            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8259                (false, false) => ui::IconName::DebugBreakpoint,
 8260                (true, false) => ui::IconName::DebugLogBreakpoint,
 8261                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8262                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8263            };
 8264
 8265            let color = if is_phantom {
 8266                Color::Hint
 8267            } else if is_rejected {
 8268                Color::Disabled
 8269            } else {
 8270                Color::Debugger
 8271            };
 8272
 8273            (color, icon)
 8274        };
 8275
 8276        let breakpoint = Arc::from(breakpoint.clone());
 8277
 8278        let alt_as_text = gpui::Keystroke {
 8279            modifiers: Modifiers::secondary_key(),
 8280            ..Default::default()
 8281        };
 8282        let primary_action_text = if breakpoint.is_disabled() {
 8283            "Enable breakpoint"
 8284        } else if is_phantom && !collides_with_existing {
 8285            "Set breakpoint"
 8286        } else {
 8287            "Unset breakpoint"
 8288        };
 8289        let focus_handle = self.focus_handle.clone();
 8290
 8291        let meta = if is_rejected {
 8292            SharedString::from("No executable code is associated with this line.")
 8293        } else if collides_with_existing && !breakpoint.is_disabled() {
 8294            SharedString::from(format!(
 8295                "{alt_as_text}-click to disable,\nright-click for more options."
 8296            ))
 8297        } else {
 8298            SharedString::from("Right-click for more options.")
 8299        };
 8300        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8301            .icon_size(IconSize::XSmall)
 8302            .size(ui::ButtonSize::None)
 8303            .when(is_rejected, |this| {
 8304                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8305            })
 8306            .icon_color(color)
 8307            .style(ButtonStyle::Transparent)
 8308            .on_click(cx.listener({
 8309                move |editor, event: &ClickEvent, window, cx| {
 8310                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8311                        BreakpointEditAction::InvertState
 8312                    } else {
 8313                        BreakpointEditAction::Toggle
 8314                    };
 8315
 8316                    window.focus(&editor.focus_handle(cx));
 8317                    editor.edit_breakpoint_at_anchor(
 8318                        position,
 8319                        breakpoint.as_ref().clone(),
 8320                        edit_action,
 8321                        cx,
 8322                    );
 8323                }
 8324            }))
 8325            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8326                editor.set_breakpoint_context_menu(
 8327                    row,
 8328                    Some(position),
 8329                    event.position(),
 8330                    window,
 8331                    cx,
 8332                );
 8333            }))
 8334            .tooltip(move |window, cx| {
 8335                Tooltip::with_meta_in(
 8336                    primary_action_text,
 8337                    Some(&ToggleBreakpoint),
 8338                    meta.clone(),
 8339                    &focus_handle,
 8340                    window,
 8341                    cx,
 8342                )
 8343            })
 8344    }
 8345
 8346    fn build_tasks_context(
 8347        project: &Entity<Project>,
 8348        buffer: &Entity<Buffer>,
 8349        buffer_row: u32,
 8350        tasks: &Arc<RunnableTasks>,
 8351        cx: &mut Context<Self>,
 8352    ) -> Task<Option<task::TaskContext>> {
 8353        let position = Point::new(buffer_row, tasks.column);
 8354        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8355        let location = Location {
 8356            buffer: buffer.clone(),
 8357            range: range_start..range_start,
 8358        };
 8359        // Fill in the environmental variables from the tree-sitter captures
 8360        let mut captured_task_variables = TaskVariables::default();
 8361        for (capture_name, value) in tasks.extra_variables.clone() {
 8362            captured_task_variables.insert(
 8363                task::VariableName::Custom(capture_name.into()),
 8364                value.clone(),
 8365            );
 8366        }
 8367        project.update(cx, |project, cx| {
 8368            project.task_store().update(cx, |task_store, cx| {
 8369                task_store.task_context_for_location(captured_task_variables, location, cx)
 8370            })
 8371        })
 8372    }
 8373
 8374    pub fn spawn_nearest_task(
 8375        &mut self,
 8376        action: &SpawnNearestTask,
 8377        window: &mut Window,
 8378        cx: &mut Context<Self>,
 8379    ) {
 8380        let Some((workspace, _)) = self.workspace.clone() else {
 8381            return;
 8382        };
 8383        let Some(project) = self.project.clone() else {
 8384            return;
 8385        };
 8386
 8387        // Try to find a closest, enclosing node using tree-sitter that has a task
 8388        let Some((buffer, buffer_row, tasks)) = self
 8389            .find_enclosing_node_task(cx)
 8390            // Or find the task that's closest in row-distance.
 8391            .or_else(|| self.find_closest_task(cx))
 8392        else {
 8393            return;
 8394        };
 8395
 8396        let reveal_strategy = action.reveal;
 8397        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8398        cx.spawn_in(window, async move |_, cx| {
 8399            let context = task_context.await?;
 8400            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8401
 8402            let resolved = &mut resolved_task.resolved;
 8403            resolved.reveal = reveal_strategy;
 8404
 8405            workspace
 8406                .update_in(cx, |workspace, window, cx| {
 8407                    workspace.schedule_resolved_task(
 8408                        task_source_kind,
 8409                        resolved_task,
 8410                        false,
 8411                        window,
 8412                        cx,
 8413                    );
 8414                })
 8415                .ok()
 8416        })
 8417        .detach();
 8418    }
 8419
 8420    fn find_closest_task(
 8421        &mut self,
 8422        cx: &mut Context<Self>,
 8423    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8424        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8425
 8426        let ((buffer_id, row), tasks) = self
 8427            .tasks
 8428            .iter()
 8429            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8430
 8431        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8432        let tasks = Arc::new(tasks.to_owned());
 8433        Some((buffer, *row, tasks))
 8434    }
 8435
 8436    fn find_enclosing_node_task(
 8437        &mut self,
 8438        cx: &mut Context<Self>,
 8439    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8440        let snapshot = self.buffer.read(cx).snapshot(cx);
 8441        let offset = self.selections.newest::<usize>(cx).head();
 8442        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8443        let buffer_id = excerpt.buffer().remote_id();
 8444
 8445        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8446        let mut cursor = layer.node().walk();
 8447
 8448        while cursor.goto_first_child_for_byte(offset).is_some() {
 8449            if cursor.node().end_byte() == offset {
 8450                cursor.goto_next_sibling();
 8451            }
 8452        }
 8453
 8454        // Ascend to the smallest ancestor that contains the range and has a task.
 8455        loop {
 8456            let node = cursor.node();
 8457            let node_range = node.byte_range();
 8458            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8459
 8460            // Check if this node contains our offset
 8461            if node_range.start <= offset && node_range.end >= offset {
 8462                // If it contains offset, check for task
 8463                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8464                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8465                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8466                }
 8467            }
 8468
 8469            if !cursor.goto_parent() {
 8470                break;
 8471            }
 8472        }
 8473        None
 8474    }
 8475
 8476    fn render_run_indicator(
 8477        &self,
 8478        _style: &EditorStyle,
 8479        is_active: bool,
 8480        row: DisplayRow,
 8481        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8482        cx: &mut Context<Self>,
 8483    ) -> IconButton {
 8484        let color = Color::Muted;
 8485        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8486
 8487        IconButton::new(
 8488            ("run_indicator", row.0 as usize),
 8489            ui::IconName::PlayOutlined,
 8490        )
 8491        .shape(ui::IconButtonShape::Square)
 8492        .icon_size(IconSize::XSmall)
 8493        .icon_color(color)
 8494        .toggle_state(is_active)
 8495        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8496            let quick_launch = match e {
 8497                ClickEvent::Keyboard(_) => true,
 8498                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8499            };
 8500
 8501            window.focus(&editor.focus_handle(cx));
 8502            editor.toggle_code_actions(
 8503                &ToggleCodeActions {
 8504                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8505                    quick_launch,
 8506                },
 8507                window,
 8508                cx,
 8509            );
 8510        }))
 8511        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8512            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8513        }))
 8514    }
 8515
 8516    pub fn context_menu_visible(&self) -> bool {
 8517        !self.edit_prediction_preview_is_active()
 8518            && self
 8519                .context_menu
 8520                .borrow()
 8521                .as_ref()
 8522                .is_some_and(|menu| menu.visible())
 8523    }
 8524
 8525    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8526        self.context_menu
 8527            .borrow()
 8528            .as_ref()
 8529            .map(|menu| menu.origin())
 8530    }
 8531
 8532    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8533        self.context_menu_options = Some(options);
 8534    }
 8535
 8536    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8537    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8538
 8539    fn render_edit_prediction_popover(
 8540        &mut self,
 8541        text_bounds: &Bounds<Pixels>,
 8542        content_origin: gpui::Point<Pixels>,
 8543        right_margin: Pixels,
 8544        editor_snapshot: &EditorSnapshot,
 8545        visible_row_range: Range<DisplayRow>,
 8546        scroll_top: f32,
 8547        scroll_bottom: f32,
 8548        line_layouts: &[LineWithInvisibles],
 8549        line_height: Pixels,
 8550        scroll_pixel_position: gpui::Point<Pixels>,
 8551        newest_selection_head: Option<DisplayPoint>,
 8552        editor_width: Pixels,
 8553        style: &EditorStyle,
 8554        window: &mut Window,
 8555        cx: &mut App,
 8556    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8557        if self.mode().is_minimap() {
 8558            return None;
 8559        }
 8560        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8561
 8562        if self.edit_prediction_visible_in_cursor_popover(true) {
 8563            return None;
 8564        }
 8565
 8566        match &active_edit_prediction.completion {
 8567            EditPrediction::Move { target, .. } => {
 8568                let target_display_point = target.to_display_point(editor_snapshot);
 8569
 8570                if self.edit_prediction_requires_modifier() {
 8571                    if !self.edit_prediction_preview_is_active() {
 8572                        return None;
 8573                    }
 8574
 8575                    self.render_edit_prediction_modifier_jump_popover(
 8576                        text_bounds,
 8577                        content_origin,
 8578                        visible_row_range,
 8579                        line_layouts,
 8580                        line_height,
 8581                        scroll_pixel_position,
 8582                        newest_selection_head,
 8583                        target_display_point,
 8584                        window,
 8585                        cx,
 8586                    )
 8587                } else {
 8588                    self.render_edit_prediction_eager_jump_popover(
 8589                        text_bounds,
 8590                        content_origin,
 8591                        editor_snapshot,
 8592                        visible_row_range,
 8593                        scroll_top,
 8594                        scroll_bottom,
 8595                        line_height,
 8596                        scroll_pixel_position,
 8597                        target_display_point,
 8598                        editor_width,
 8599                        window,
 8600                        cx,
 8601                    )
 8602                }
 8603            }
 8604            EditPrediction::Edit {
 8605                display_mode: EditDisplayMode::Inline,
 8606                ..
 8607            } => None,
 8608            EditPrediction::Edit {
 8609                display_mode: EditDisplayMode::TabAccept,
 8610                edits,
 8611                ..
 8612            } => {
 8613                let range = &edits.first()?.0;
 8614                let target_display_point = range.end.to_display_point(editor_snapshot);
 8615
 8616                self.render_edit_prediction_end_of_line_popover(
 8617                    "Accept",
 8618                    editor_snapshot,
 8619                    visible_row_range,
 8620                    target_display_point,
 8621                    line_height,
 8622                    scroll_pixel_position,
 8623                    content_origin,
 8624                    editor_width,
 8625                    window,
 8626                    cx,
 8627                )
 8628            }
 8629            EditPrediction::Edit {
 8630                edits,
 8631                edit_preview,
 8632                display_mode: EditDisplayMode::DiffPopover,
 8633                snapshot,
 8634            } => self.render_edit_prediction_diff_popover(
 8635                text_bounds,
 8636                content_origin,
 8637                right_margin,
 8638                editor_snapshot,
 8639                visible_row_range,
 8640                line_layouts,
 8641                line_height,
 8642                scroll_pixel_position,
 8643                newest_selection_head,
 8644                editor_width,
 8645                style,
 8646                edits,
 8647                edit_preview,
 8648                snapshot,
 8649                window,
 8650                cx,
 8651            ),
 8652        }
 8653    }
 8654
 8655    fn render_edit_prediction_modifier_jump_popover(
 8656        &mut self,
 8657        text_bounds: &Bounds<Pixels>,
 8658        content_origin: gpui::Point<Pixels>,
 8659        visible_row_range: Range<DisplayRow>,
 8660        line_layouts: &[LineWithInvisibles],
 8661        line_height: Pixels,
 8662        scroll_pixel_position: gpui::Point<Pixels>,
 8663        newest_selection_head: Option<DisplayPoint>,
 8664        target_display_point: DisplayPoint,
 8665        window: &mut Window,
 8666        cx: &mut App,
 8667    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8668        let scrolled_content_origin =
 8669            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8670
 8671        const SCROLL_PADDING_Y: Pixels = px(12.);
 8672
 8673        if target_display_point.row() < visible_row_range.start {
 8674            return self.render_edit_prediction_scroll_popover(
 8675                |_| SCROLL_PADDING_Y,
 8676                IconName::ArrowUp,
 8677                visible_row_range,
 8678                line_layouts,
 8679                newest_selection_head,
 8680                scrolled_content_origin,
 8681                window,
 8682                cx,
 8683            );
 8684        } else if target_display_point.row() >= visible_row_range.end {
 8685            return self.render_edit_prediction_scroll_popover(
 8686                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8687                IconName::ArrowDown,
 8688                visible_row_range,
 8689                line_layouts,
 8690                newest_selection_head,
 8691                scrolled_content_origin,
 8692                window,
 8693                cx,
 8694            );
 8695        }
 8696
 8697        const POLE_WIDTH: Pixels = px(2.);
 8698
 8699        let line_layout =
 8700            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8701        let target_column = target_display_point.column() as usize;
 8702
 8703        let target_x = line_layout.x_for_index(target_column);
 8704        let target_y =
 8705            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8706
 8707        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8708
 8709        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8710        border_color.l += 0.001;
 8711
 8712        let mut element = v_flex()
 8713            .items_end()
 8714            .when(flag_on_right, |el| el.items_start())
 8715            .child(if flag_on_right {
 8716                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8717                    .rounded_bl(px(0.))
 8718                    .rounded_tl(px(0.))
 8719                    .border_l_2()
 8720                    .border_color(border_color)
 8721            } else {
 8722                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8723                    .rounded_br(px(0.))
 8724                    .rounded_tr(px(0.))
 8725                    .border_r_2()
 8726                    .border_color(border_color)
 8727            })
 8728            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8729            .into_any();
 8730
 8731        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8732
 8733        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8734            - point(
 8735                if flag_on_right {
 8736                    POLE_WIDTH
 8737                } else {
 8738                    size.width - POLE_WIDTH
 8739                },
 8740                size.height - line_height,
 8741            );
 8742
 8743        origin.x = origin.x.max(content_origin.x);
 8744
 8745        element.prepaint_at(origin, window, cx);
 8746
 8747        Some((element, origin))
 8748    }
 8749
 8750    fn render_edit_prediction_scroll_popover(
 8751        &mut self,
 8752        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8753        scroll_icon: IconName,
 8754        visible_row_range: Range<DisplayRow>,
 8755        line_layouts: &[LineWithInvisibles],
 8756        newest_selection_head: Option<DisplayPoint>,
 8757        scrolled_content_origin: gpui::Point<Pixels>,
 8758        window: &mut Window,
 8759        cx: &mut App,
 8760    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8761        let mut element = self
 8762            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8763            .into_any();
 8764
 8765        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8766
 8767        let cursor = newest_selection_head?;
 8768        let cursor_row_layout =
 8769            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8770        let cursor_column = cursor.column() as usize;
 8771
 8772        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8773
 8774        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8775
 8776        element.prepaint_at(origin, window, cx);
 8777        Some((element, origin))
 8778    }
 8779
 8780    fn render_edit_prediction_eager_jump_popover(
 8781        &mut self,
 8782        text_bounds: &Bounds<Pixels>,
 8783        content_origin: gpui::Point<Pixels>,
 8784        editor_snapshot: &EditorSnapshot,
 8785        visible_row_range: Range<DisplayRow>,
 8786        scroll_top: f32,
 8787        scroll_bottom: f32,
 8788        line_height: Pixels,
 8789        scroll_pixel_position: gpui::Point<Pixels>,
 8790        target_display_point: DisplayPoint,
 8791        editor_width: Pixels,
 8792        window: &mut Window,
 8793        cx: &mut App,
 8794    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8795        if target_display_point.row().as_f32() < scroll_top {
 8796            let mut element = self
 8797                .render_edit_prediction_line_popover(
 8798                    "Jump to Edit",
 8799                    Some(IconName::ArrowUp),
 8800                    window,
 8801                    cx,
 8802                )?
 8803                .into_any();
 8804
 8805            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8806            let offset = point(
 8807                (text_bounds.size.width - size.width) / 2.,
 8808                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8809            );
 8810
 8811            let origin = text_bounds.origin + offset;
 8812            element.prepaint_at(origin, window, cx);
 8813            Some((element, origin))
 8814        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8815            let mut element = self
 8816                .render_edit_prediction_line_popover(
 8817                    "Jump to Edit",
 8818                    Some(IconName::ArrowDown),
 8819                    window,
 8820                    cx,
 8821                )?
 8822                .into_any();
 8823
 8824            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8825            let offset = point(
 8826                (text_bounds.size.width - size.width) / 2.,
 8827                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8828            );
 8829
 8830            let origin = text_bounds.origin + offset;
 8831            element.prepaint_at(origin, window, cx);
 8832            Some((element, origin))
 8833        } else {
 8834            self.render_edit_prediction_end_of_line_popover(
 8835                "Jump to Edit",
 8836                editor_snapshot,
 8837                visible_row_range,
 8838                target_display_point,
 8839                line_height,
 8840                scroll_pixel_position,
 8841                content_origin,
 8842                editor_width,
 8843                window,
 8844                cx,
 8845            )
 8846        }
 8847    }
 8848
 8849    fn render_edit_prediction_end_of_line_popover(
 8850        self: &mut Editor,
 8851        label: &'static str,
 8852        editor_snapshot: &EditorSnapshot,
 8853        visible_row_range: Range<DisplayRow>,
 8854        target_display_point: DisplayPoint,
 8855        line_height: Pixels,
 8856        scroll_pixel_position: gpui::Point<Pixels>,
 8857        content_origin: gpui::Point<Pixels>,
 8858        editor_width: Pixels,
 8859        window: &mut Window,
 8860        cx: &mut App,
 8861    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8862        let target_line_end = DisplayPoint::new(
 8863            target_display_point.row(),
 8864            editor_snapshot.line_len(target_display_point.row()),
 8865        );
 8866
 8867        let mut element = self
 8868            .render_edit_prediction_line_popover(label, None, window, cx)?
 8869            .into_any();
 8870
 8871        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8872
 8873        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8874
 8875        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8876        let mut origin = start_point
 8877            + line_origin
 8878            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8879        origin.x = origin.x.max(content_origin.x);
 8880
 8881        let max_x = content_origin.x + editor_width - size.width;
 8882
 8883        if origin.x > max_x {
 8884            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8885
 8886            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8887                origin.y += offset;
 8888                IconName::ArrowUp
 8889            } else {
 8890                origin.y -= offset;
 8891                IconName::ArrowDown
 8892            };
 8893
 8894            element = self
 8895                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8896                .into_any();
 8897
 8898            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8899
 8900            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8901        }
 8902
 8903        element.prepaint_at(origin, window, cx);
 8904        Some((element, origin))
 8905    }
 8906
 8907    fn render_edit_prediction_diff_popover(
 8908        self: &Editor,
 8909        text_bounds: &Bounds<Pixels>,
 8910        content_origin: gpui::Point<Pixels>,
 8911        right_margin: Pixels,
 8912        editor_snapshot: &EditorSnapshot,
 8913        visible_row_range: Range<DisplayRow>,
 8914        line_layouts: &[LineWithInvisibles],
 8915        line_height: Pixels,
 8916        scroll_pixel_position: gpui::Point<Pixels>,
 8917        newest_selection_head: Option<DisplayPoint>,
 8918        editor_width: Pixels,
 8919        style: &EditorStyle,
 8920        edits: &Vec<(Range<Anchor>, String)>,
 8921        edit_preview: &Option<language::EditPreview>,
 8922        snapshot: &language::BufferSnapshot,
 8923        window: &mut Window,
 8924        cx: &mut App,
 8925    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8926        let edit_start = edits
 8927            .first()
 8928            .unwrap()
 8929            .0
 8930            .start
 8931            .to_display_point(editor_snapshot);
 8932        let edit_end = edits
 8933            .last()
 8934            .unwrap()
 8935            .0
 8936            .end
 8937            .to_display_point(editor_snapshot);
 8938
 8939        let is_visible = visible_row_range.contains(&edit_start.row())
 8940            || visible_row_range.contains(&edit_end.row());
 8941        if !is_visible {
 8942            return None;
 8943        }
 8944
 8945        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8946            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8947        } else {
 8948            // Fallback for providers without edit_preview
 8949            crate::edit_prediction_fallback_text(edits, cx)
 8950        };
 8951
 8952        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8953        let line_count = highlighted_edits.text.lines().count();
 8954
 8955        const BORDER_WIDTH: Pixels = px(1.);
 8956
 8957        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8958        let has_keybind = keybind.is_some();
 8959
 8960        let mut element = h_flex()
 8961            .items_start()
 8962            .child(
 8963                h_flex()
 8964                    .bg(cx.theme().colors().editor_background)
 8965                    .border(BORDER_WIDTH)
 8966                    .shadow_xs()
 8967                    .border_color(cx.theme().colors().border)
 8968                    .rounded_l_lg()
 8969                    .when(line_count > 1, |el| el.rounded_br_lg())
 8970                    .pr_1()
 8971                    .child(styled_text),
 8972            )
 8973            .child(
 8974                h_flex()
 8975                    .h(line_height + BORDER_WIDTH * 2.)
 8976                    .px_1p5()
 8977                    .gap_1()
 8978                    // Workaround: For some reason, there's a gap if we don't do this
 8979                    .ml(-BORDER_WIDTH)
 8980                    .shadow(vec![gpui::BoxShadow {
 8981                        color: gpui::black().opacity(0.05),
 8982                        offset: point(px(1.), px(1.)),
 8983                        blur_radius: px(2.),
 8984                        spread_radius: px(0.),
 8985                    }])
 8986                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8987                    .border(BORDER_WIDTH)
 8988                    .border_color(cx.theme().colors().border)
 8989                    .rounded_r_lg()
 8990                    .id("edit_prediction_diff_popover_keybind")
 8991                    .when(!has_keybind, |el| {
 8992                        let status_colors = cx.theme().status();
 8993
 8994                        el.bg(status_colors.error_background)
 8995                            .border_color(status_colors.error.opacity(0.6))
 8996                            .child(Icon::new(IconName::Info).color(Color::Error))
 8997                            .cursor_default()
 8998                            .hoverable_tooltip(move |_window, cx| {
 8999                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9000                            })
 9001                    })
 9002                    .children(keybind),
 9003            )
 9004            .into_any();
 9005
 9006        let longest_row =
 9007            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9008        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9009            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9010        } else {
 9011            layout_line(
 9012                longest_row,
 9013                editor_snapshot,
 9014                style,
 9015                editor_width,
 9016                |_| false,
 9017                window,
 9018                cx,
 9019            )
 9020            .width
 9021        };
 9022
 9023        let viewport_bounds =
 9024            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9025                right: -right_margin,
 9026                ..Default::default()
 9027            });
 9028
 9029        let x_after_longest =
 9030            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9031                - scroll_pixel_position.x;
 9032
 9033        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9034
 9035        // Fully visible if it can be displayed within the window (allow overlapping other
 9036        // panes). However, this is only allowed if the popover starts within text_bounds.
 9037        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9038            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9039
 9040        let mut origin = if can_position_to_the_right {
 9041            point(
 9042                x_after_longest,
 9043                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9044                    - scroll_pixel_position.y,
 9045            )
 9046        } else {
 9047            let cursor_row = newest_selection_head.map(|head| head.row());
 9048            let above_edit = edit_start
 9049                .row()
 9050                .0
 9051                .checked_sub(line_count as u32)
 9052                .map(DisplayRow);
 9053            let below_edit = Some(edit_end.row() + 1);
 9054            let above_cursor =
 9055                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9056            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9057
 9058            // Place the edit popover adjacent to the edit if there is a location
 9059            // available that is onscreen and does not obscure the cursor. Otherwise,
 9060            // place it adjacent to the cursor.
 9061            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9062                .into_iter()
 9063                .flatten()
 9064                .find(|&start_row| {
 9065                    let end_row = start_row + line_count as u32;
 9066                    visible_row_range.contains(&start_row)
 9067                        && visible_row_range.contains(&end_row)
 9068                        && cursor_row
 9069                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9070                })?;
 9071
 9072            content_origin
 9073                + point(
 9074                    -scroll_pixel_position.x,
 9075                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9076                )
 9077        };
 9078
 9079        origin.x -= BORDER_WIDTH;
 9080
 9081        window.defer_draw(element, origin, 1);
 9082
 9083        // Do not return an element, since it will already be drawn due to defer_draw.
 9084        None
 9085    }
 9086
 9087    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9088        px(30.)
 9089    }
 9090
 9091    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9092        if self.read_only(cx) {
 9093            cx.theme().players().read_only()
 9094        } else {
 9095            self.style.as_ref().unwrap().local_player
 9096        }
 9097    }
 9098
 9099    fn render_edit_prediction_accept_keybind(
 9100        &self,
 9101        window: &mut Window,
 9102        cx: &App,
 9103    ) -> Option<AnyElement> {
 9104        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9105        let accept_keystroke = accept_binding.keystroke()?;
 9106
 9107        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9108
 9109        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9110            Color::Accent
 9111        } else {
 9112            Color::Muted
 9113        };
 9114
 9115        h_flex()
 9116            .px_0p5()
 9117            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9118            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9119            .text_size(TextSize::XSmall.rems(cx))
 9120            .child(h_flex().children(ui::render_modifiers(
 9121                accept_keystroke.modifiers(),
 9122                PlatformStyle::platform(),
 9123                Some(modifiers_color),
 9124                Some(IconSize::XSmall.rems().into()),
 9125                true,
 9126            )))
 9127            .when(is_platform_style_mac, |parent| {
 9128                parent.child(accept_keystroke.key().to_string())
 9129            })
 9130            .when(!is_platform_style_mac, |parent| {
 9131                parent.child(
 9132                    Key::new(
 9133                        util::capitalize(accept_keystroke.key()),
 9134                        Some(Color::Default),
 9135                    )
 9136                    .size(Some(IconSize::XSmall.rems().into())),
 9137                )
 9138            })
 9139            .into_any()
 9140            .into()
 9141    }
 9142
 9143    fn render_edit_prediction_line_popover(
 9144        &self,
 9145        label: impl Into<SharedString>,
 9146        icon: Option<IconName>,
 9147        window: &mut Window,
 9148        cx: &App,
 9149    ) -> Option<Stateful<Div>> {
 9150        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9151
 9152        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9153        let has_keybind = keybind.is_some();
 9154
 9155        let result = h_flex()
 9156            .id("ep-line-popover")
 9157            .py_0p5()
 9158            .pl_1()
 9159            .pr(padding_right)
 9160            .gap_1()
 9161            .rounded_md()
 9162            .border_1()
 9163            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9164            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9165            .shadow_xs()
 9166            .when(!has_keybind, |el| {
 9167                let status_colors = cx.theme().status();
 9168
 9169                el.bg(status_colors.error_background)
 9170                    .border_color(status_colors.error.opacity(0.6))
 9171                    .pl_2()
 9172                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9173                    .cursor_default()
 9174                    .hoverable_tooltip(move |_window, cx| {
 9175                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9176                    })
 9177            })
 9178            .children(keybind)
 9179            .child(
 9180                Label::new(label)
 9181                    .size(LabelSize::Small)
 9182                    .when(!has_keybind, |el| {
 9183                        el.color(cx.theme().status().error.into()).strikethrough()
 9184                    }),
 9185            )
 9186            .when(!has_keybind, |el| {
 9187                el.child(
 9188                    h_flex().ml_1().child(
 9189                        Icon::new(IconName::Info)
 9190                            .size(IconSize::Small)
 9191                            .color(cx.theme().status().error.into()),
 9192                    ),
 9193                )
 9194            })
 9195            .when_some(icon, |element, icon| {
 9196                element.child(
 9197                    div()
 9198                        .mt(px(1.5))
 9199                        .child(Icon::new(icon).size(IconSize::Small)),
 9200                )
 9201            });
 9202
 9203        Some(result)
 9204    }
 9205
 9206    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9207        let accent_color = cx.theme().colors().text_accent;
 9208        let editor_bg_color = cx.theme().colors().editor_background;
 9209        editor_bg_color.blend(accent_color.opacity(0.1))
 9210    }
 9211
 9212    fn edit_prediction_callout_popover_border_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.6))
 9216    }
 9217    fn get_prediction_provider_icon_name(
 9218        provider: &Option<RegisteredEditPredictionProvider>,
 9219    ) -> IconName {
 9220        match provider {
 9221            Some(provider) => match provider.provider.name() {
 9222                "copilot" => IconName::Copilot,
 9223                "supermaven" => IconName::Supermaven,
 9224                _ => IconName::ZedPredict,
 9225            },
 9226            None => IconName::ZedPredict,
 9227        }
 9228    }
 9229
 9230    fn render_edit_prediction_cursor_popover(
 9231        &self,
 9232        min_width: Pixels,
 9233        max_width: Pixels,
 9234        cursor_point: Point,
 9235        style: &EditorStyle,
 9236        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9237        _window: &Window,
 9238        cx: &mut Context<Editor>,
 9239    ) -> Option<AnyElement> {
 9240        let provider = self.edit_prediction_provider.as_ref()?;
 9241        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9242
 9243        let is_refreshing = provider.provider.is_refreshing(cx);
 9244
 9245        fn pending_completion_container(icon: IconName) -> Div {
 9246            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9247        }
 9248
 9249        let completion = match &self.active_edit_prediction {
 9250            Some(prediction) => {
 9251                if !self.has_visible_completions_menu() {
 9252                    const RADIUS: Pixels = px(6.);
 9253                    const BORDER_WIDTH: Pixels = px(1.);
 9254
 9255                    return Some(
 9256                        h_flex()
 9257                            .elevation_2(cx)
 9258                            .border(BORDER_WIDTH)
 9259                            .border_color(cx.theme().colors().border)
 9260                            .when(accept_keystroke.is_none(), |el| {
 9261                                el.border_color(cx.theme().status().error)
 9262                            })
 9263                            .rounded(RADIUS)
 9264                            .rounded_tl(px(0.))
 9265                            .overflow_hidden()
 9266                            .child(div().px_1p5().child(match &prediction.completion {
 9267                                EditPrediction::Move { target, snapshot } => {
 9268                                    use text::ToPoint as _;
 9269                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9270                                    {
 9271                                        Icon::new(IconName::ZedPredictDown)
 9272                                    } else {
 9273                                        Icon::new(IconName::ZedPredictUp)
 9274                                    }
 9275                                }
 9276                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9277                            }))
 9278                            .child(
 9279                                h_flex()
 9280                                    .gap_1()
 9281                                    .py_1()
 9282                                    .px_2()
 9283                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9284                                    .border_l_1()
 9285                                    .border_color(cx.theme().colors().border)
 9286                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9287                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9288                                        el.child(
 9289                                            Label::new("Hold")
 9290                                                .size(LabelSize::Small)
 9291                                                .when(accept_keystroke.is_none(), |el| {
 9292                                                    el.strikethrough()
 9293                                                })
 9294                                                .line_height_style(LineHeightStyle::UiLabel),
 9295                                        )
 9296                                    })
 9297                                    .id("edit_prediction_cursor_popover_keybind")
 9298                                    .when(accept_keystroke.is_none(), |el| {
 9299                                        let status_colors = cx.theme().status();
 9300
 9301                                        el.bg(status_colors.error_background)
 9302                                            .border_color(status_colors.error.opacity(0.6))
 9303                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9304                                            .cursor_default()
 9305                                            .hoverable_tooltip(move |_window, cx| {
 9306                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9307                                                    .into()
 9308                                            })
 9309                                    })
 9310                                    .when_some(
 9311                                        accept_keystroke.as_ref(),
 9312                                        |el, accept_keystroke| {
 9313                                            el.child(h_flex().children(ui::render_modifiers(
 9314                                                accept_keystroke.modifiers(),
 9315                                                PlatformStyle::platform(),
 9316                                                Some(Color::Default),
 9317                                                Some(IconSize::XSmall.rems().into()),
 9318                                                false,
 9319                                            )))
 9320                                        },
 9321                                    ),
 9322                            )
 9323                            .into_any(),
 9324                    );
 9325                }
 9326
 9327                self.render_edit_prediction_cursor_popover_preview(
 9328                    prediction,
 9329                    cursor_point,
 9330                    style,
 9331                    cx,
 9332                )?
 9333            }
 9334
 9335            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9336                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9337                    stale_completion,
 9338                    cursor_point,
 9339                    style,
 9340                    cx,
 9341                )?,
 9342
 9343                None => pending_completion_container(provider_icon)
 9344                    .child(Label::new("...").size(LabelSize::Small)),
 9345            },
 9346
 9347            None => pending_completion_container(provider_icon)
 9348                .child(Label::new("...").size(LabelSize::Small)),
 9349        };
 9350
 9351        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9352            completion
 9353                .with_animation(
 9354                    "loading-completion",
 9355                    Animation::new(Duration::from_secs(2))
 9356                        .repeat()
 9357                        .with_easing(pulsating_between(0.4, 0.8)),
 9358                    |label, delta| label.opacity(delta),
 9359                )
 9360                .into_any_element()
 9361        } else {
 9362            completion.into_any_element()
 9363        };
 9364
 9365        let has_completion = self.active_edit_prediction.is_some();
 9366
 9367        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9368        Some(
 9369            h_flex()
 9370                .min_w(min_width)
 9371                .max_w(max_width)
 9372                .flex_1()
 9373                .elevation_2(cx)
 9374                .border_color(cx.theme().colors().border)
 9375                .child(
 9376                    div()
 9377                        .flex_1()
 9378                        .py_1()
 9379                        .px_2()
 9380                        .overflow_hidden()
 9381                        .child(completion),
 9382                )
 9383                .when_some(accept_keystroke, |el, accept_keystroke| {
 9384                    if !accept_keystroke.modifiers().modified() {
 9385                        return el;
 9386                    }
 9387
 9388                    el.child(
 9389                        h_flex()
 9390                            .h_full()
 9391                            .border_l_1()
 9392                            .rounded_r_lg()
 9393                            .border_color(cx.theme().colors().border)
 9394                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9395                            .gap_1()
 9396                            .py_1()
 9397                            .px_2()
 9398                            .child(
 9399                                h_flex()
 9400                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9401                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9402                                    .child(h_flex().children(ui::render_modifiers(
 9403                                        accept_keystroke.modifiers(),
 9404                                        PlatformStyle::platform(),
 9405                                        Some(if !has_completion {
 9406                                            Color::Muted
 9407                                        } else {
 9408                                            Color::Default
 9409                                        }),
 9410                                        None,
 9411                                        false,
 9412                                    ))),
 9413                            )
 9414                            .child(Label::new("Preview").into_any_element())
 9415                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9416                    )
 9417                })
 9418                .into_any(),
 9419        )
 9420    }
 9421
 9422    fn render_edit_prediction_cursor_popover_preview(
 9423        &self,
 9424        completion: &EditPredictionState,
 9425        cursor_point: Point,
 9426        style: &EditorStyle,
 9427        cx: &mut Context<Editor>,
 9428    ) -> Option<Div> {
 9429        use text::ToPoint as _;
 9430
 9431        fn render_relative_row_jump(
 9432            prefix: impl Into<String>,
 9433            current_row: u32,
 9434            target_row: u32,
 9435        ) -> Div {
 9436            let (row_diff, arrow) = if target_row < current_row {
 9437                (current_row - target_row, IconName::ArrowUp)
 9438            } else {
 9439                (target_row - current_row, IconName::ArrowDown)
 9440            };
 9441
 9442            h_flex()
 9443                .child(
 9444                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9445                        .color(Color::Muted)
 9446                        .size(LabelSize::Small),
 9447                )
 9448                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9449        }
 9450
 9451        let supports_jump = self
 9452            .edit_prediction_provider
 9453            .as_ref()
 9454            .map(|provider| provider.provider.supports_jump_to_edit())
 9455            .unwrap_or(true);
 9456
 9457        match &completion.completion {
 9458            EditPrediction::Move {
 9459                target, snapshot, ..
 9460            } => {
 9461                if !supports_jump {
 9462                    return None;
 9463                }
 9464
 9465                Some(
 9466                    h_flex()
 9467                        .px_2()
 9468                        .gap_2()
 9469                        .flex_1()
 9470                        .child(
 9471                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9472                                Icon::new(IconName::ZedPredictDown)
 9473                            } else {
 9474                                Icon::new(IconName::ZedPredictUp)
 9475                            },
 9476                        )
 9477                        .child(Label::new("Jump to Edit")),
 9478                )
 9479            }
 9480
 9481            EditPrediction::Edit {
 9482                edits,
 9483                edit_preview,
 9484                snapshot,
 9485                display_mode: _,
 9486            } => {
 9487                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9488
 9489                let (highlighted_edits, has_more_lines) =
 9490                    if let Some(edit_preview) = edit_preview.as_ref() {
 9491                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9492                            .first_line_preview()
 9493                    } else {
 9494                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9495                    };
 9496
 9497                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9498                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9499
 9500                let preview = h_flex()
 9501                    .gap_1()
 9502                    .min_w_16()
 9503                    .child(styled_text)
 9504                    .when(has_more_lines, |parent| parent.child(""));
 9505
 9506                let left = if supports_jump && first_edit_row != cursor_point.row {
 9507                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9508                        .into_any_element()
 9509                } else {
 9510                    let icon_name =
 9511                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9512                    Icon::new(icon_name).into_any_element()
 9513                };
 9514
 9515                Some(
 9516                    h_flex()
 9517                        .h_full()
 9518                        .flex_1()
 9519                        .gap_2()
 9520                        .pr_1()
 9521                        .overflow_x_hidden()
 9522                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9523                        .child(left)
 9524                        .child(preview),
 9525                )
 9526            }
 9527        }
 9528    }
 9529
 9530    pub fn render_context_menu(
 9531        &self,
 9532        style: &EditorStyle,
 9533        max_height_in_lines: u32,
 9534        window: &mut Window,
 9535        cx: &mut Context<Editor>,
 9536    ) -> Option<AnyElement> {
 9537        let menu = self.context_menu.borrow();
 9538        let menu = menu.as_ref()?;
 9539        if !menu.visible() {
 9540            return None;
 9541        };
 9542        Some(menu.render(style, max_height_in_lines, window, cx))
 9543    }
 9544
 9545    fn render_context_menu_aside(
 9546        &mut self,
 9547        max_size: Size<Pixels>,
 9548        window: &mut Window,
 9549        cx: &mut Context<Editor>,
 9550    ) -> Option<AnyElement> {
 9551        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9552            if menu.visible() {
 9553                menu.render_aside(max_size, window, cx)
 9554            } else {
 9555                None
 9556            }
 9557        })
 9558    }
 9559
 9560    fn hide_context_menu(
 9561        &mut self,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) -> Option<CodeContextMenu> {
 9565        cx.notify();
 9566        self.completion_tasks.clear();
 9567        let context_menu = self.context_menu.borrow_mut().take();
 9568        self.stale_edit_prediction_in_menu.take();
 9569        self.update_visible_edit_prediction(window, cx);
 9570        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9571            && let Some(completion_provider) = &self.completion_provider
 9572        {
 9573            completion_provider.selection_changed(None, window, cx);
 9574        }
 9575        context_menu
 9576    }
 9577
 9578    fn show_snippet_choices(
 9579        &mut self,
 9580        choices: &Vec<String>,
 9581        selection: Range<Anchor>,
 9582        cx: &mut Context<Self>,
 9583    ) {
 9584        let Some((_, buffer, _)) = self
 9585            .buffer()
 9586            .read(cx)
 9587            .excerpt_containing(selection.start, cx)
 9588        else {
 9589            return;
 9590        };
 9591        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9592        else {
 9593            return;
 9594        };
 9595        if buffer != end_buffer {
 9596            log::error!("expected anchor range to have matching buffer IDs");
 9597            return;
 9598        }
 9599
 9600        let id = post_inc(&mut self.next_completion_id);
 9601        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9602        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9603            CompletionsMenu::new_snippet_choices(
 9604                id,
 9605                true,
 9606                choices,
 9607                selection,
 9608                buffer,
 9609                snippet_sort_order,
 9610            ),
 9611        ));
 9612    }
 9613
 9614    pub fn insert_snippet(
 9615        &mut self,
 9616        insertion_ranges: &[Range<usize>],
 9617        snippet: Snippet,
 9618        window: &mut Window,
 9619        cx: &mut Context<Self>,
 9620    ) -> Result<()> {
 9621        struct Tabstop<T> {
 9622            is_end_tabstop: bool,
 9623            ranges: Vec<Range<T>>,
 9624            choices: Option<Vec<String>>,
 9625        }
 9626
 9627        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9628            let snippet_text: Arc<str> = snippet.text.clone().into();
 9629            let edits = insertion_ranges
 9630                .iter()
 9631                .cloned()
 9632                .map(|range| (range, snippet_text.clone()));
 9633            let autoindent_mode = AutoindentMode::Block {
 9634                original_indent_columns: Vec::new(),
 9635            };
 9636            buffer.edit(edits, Some(autoindent_mode), cx);
 9637
 9638            let snapshot = &*buffer.read(cx);
 9639            let snippet = &snippet;
 9640            snippet
 9641                .tabstops
 9642                .iter()
 9643                .map(|tabstop| {
 9644                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9645                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9646                    });
 9647                    let mut tabstop_ranges = tabstop
 9648                        .ranges
 9649                        .iter()
 9650                        .flat_map(|tabstop_range| {
 9651                            let mut delta = 0_isize;
 9652                            insertion_ranges.iter().map(move |insertion_range| {
 9653                                let insertion_start = insertion_range.start as isize + delta;
 9654                                delta +=
 9655                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9656
 9657                                let start = ((insertion_start + tabstop_range.start) as usize)
 9658                                    .min(snapshot.len());
 9659                                let end = ((insertion_start + tabstop_range.end) as usize)
 9660                                    .min(snapshot.len());
 9661                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9662                            })
 9663                        })
 9664                        .collect::<Vec<_>>();
 9665                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9666
 9667                    Tabstop {
 9668                        is_end_tabstop,
 9669                        ranges: tabstop_ranges,
 9670                        choices: tabstop.choices.clone(),
 9671                    }
 9672                })
 9673                .collect::<Vec<_>>()
 9674        });
 9675        if let Some(tabstop) = tabstops.first() {
 9676            self.change_selections(Default::default(), window, cx, |s| {
 9677                // Reverse order so that the first range is the newest created selection.
 9678                // Completions will use it and autoscroll will prioritize it.
 9679                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9680            });
 9681
 9682            if let Some(choices) = &tabstop.choices
 9683                && let Some(selection) = tabstop.ranges.first()
 9684            {
 9685                self.show_snippet_choices(choices, selection.clone(), cx)
 9686            }
 9687
 9688            // If we're already at the last tabstop and it's at the end of the snippet,
 9689            // we're done, we don't need to keep the state around.
 9690            if !tabstop.is_end_tabstop {
 9691                let choices = tabstops
 9692                    .iter()
 9693                    .map(|tabstop| tabstop.choices.clone())
 9694                    .collect();
 9695
 9696                let ranges = tabstops
 9697                    .into_iter()
 9698                    .map(|tabstop| tabstop.ranges)
 9699                    .collect::<Vec<_>>();
 9700
 9701                self.snippet_stack.push(SnippetState {
 9702                    active_index: 0,
 9703                    ranges,
 9704                    choices,
 9705                });
 9706            }
 9707
 9708            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9709            if self.autoclose_regions.is_empty() {
 9710                let snapshot = self.buffer.read(cx).snapshot(cx);
 9711                let mut all_selections = self.selections.all::<Point>(cx);
 9712                for selection in &mut all_selections {
 9713                    let selection_head = selection.head();
 9714                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9715                        continue;
 9716                    };
 9717
 9718                    let mut bracket_pair = None;
 9719                    let max_lookup_length = scope
 9720                        .brackets()
 9721                        .map(|(pair, _)| {
 9722                            pair.start
 9723                                .as_str()
 9724                                .chars()
 9725                                .count()
 9726                                .max(pair.end.as_str().chars().count())
 9727                        })
 9728                        .max();
 9729                    if let Some(max_lookup_length) = max_lookup_length {
 9730                        let next_text = snapshot
 9731                            .chars_at(selection_head)
 9732                            .take(max_lookup_length)
 9733                            .collect::<String>();
 9734                        let prev_text = snapshot
 9735                            .reversed_chars_at(selection_head)
 9736                            .take(max_lookup_length)
 9737                            .collect::<String>();
 9738
 9739                        for (pair, enabled) in scope.brackets() {
 9740                            if enabled
 9741                                && pair.close
 9742                                && prev_text.starts_with(pair.start.as_str())
 9743                                && next_text.starts_with(pair.end.as_str())
 9744                            {
 9745                                bracket_pair = Some(pair.clone());
 9746                                break;
 9747                            }
 9748                        }
 9749                    }
 9750
 9751                    if let Some(pair) = bracket_pair {
 9752                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9753                        let autoclose_enabled =
 9754                            self.use_autoclose && snapshot_settings.use_autoclose;
 9755                        if autoclose_enabled {
 9756                            let start = snapshot.anchor_after(selection_head);
 9757                            let end = snapshot.anchor_after(selection_head);
 9758                            self.autoclose_regions.push(AutocloseRegion {
 9759                                selection_id: selection.id,
 9760                                range: start..end,
 9761                                pair,
 9762                            });
 9763                        }
 9764                    }
 9765                }
 9766            }
 9767        }
 9768        Ok(())
 9769    }
 9770
 9771    pub fn move_to_next_snippet_tabstop(
 9772        &mut self,
 9773        window: &mut Window,
 9774        cx: &mut Context<Self>,
 9775    ) -> bool {
 9776        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9777    }
 9778
 9779    pub fn move_to_prev_snippet_tabstop(
 9780        &mut self,
 9781        window: &mut Window,
 9782        cx: &mut Context<Self>,
 9783    ) -> bool {
 9784        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9785    }
 9786
 9787    pub fn move_to_snippet_tabstop(
 9788        &mut self,
 9789        bias: Bias,
 9790        window: &mut Window,
 9791        cx: &mut Context<Self>,
 9792    ) -> bool {
 9793        if let Some(mut snippet) = self.snippet_stack.pop() {
 9794            match bias {
 9795                Bias::Left => {
 9796                    if snippet.active_index > 0 {
 9797                        snippet.active_index -= 1;
 9798                    } else {
 9799                        self.snippet_stack.push(snippet);
 9800                        return false;
 9801                    }
 9802                }
 9803                Bias::Right => {
 9804                    if snippet.active_index + 1 < snippet.ranges.len() {
 9805                        snippet.active_index += 1;
 9806                    } else {
 9807                        self.snippet_stack.push(snippet);
 9808                        return false;
 9809                    }
 9810                }
 9811            }
 9812            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9813                self.change_selections(Default::default(), window, cx, |s| {
 9814                    // Reverse order so that the first range is the newest created selection.
 9815                    // Completions will use it and autoscroll will prioritize it.
 9816                    s.select_ranges(current_ranges.iter().rev().cloned())
 9817                });
 9818
 9819                if let Some(choices) = &snippet.choices[snippet.active_index]
 9820                    && let Some(selection) = current_ranges.first()
 9821                {
 9822                    self.show_snippet_choices(choices, selection.clone(), cx);
 9823                }
 9824
 9825                // If snippet state is not at the last tabstop, push it back on the stack
 9826                if snippet.active_index + 1 < snippet.ranges.len() {
 9827                    self.snippet_stack.push(snippet);
 9828                }
 9829                return true;
 9830            }
 9831        }
 9832
 9833        false
 9834    }
 9835
 9836    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9837        self.transact(window, cx, |this, window, cx| {
 9838            this.select_all(&SelectAll, window, cx);
 9839            this.insert("", window, cx);
 9840        });
 9841    }
 9842
 9843    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9844        if self.read_only(cx) {
 9845            return;
 9846        }
 9847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9848        self.transact(window, cx, |this, window, cx| {
 9849            this.select_autoclose_pair(window, cx);
 9850            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9851            if !this.linked_edit_ranges.is_empty() {
 9852                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9853                let snapshot = this.buffer.read(cx).snapshot(cx);
 9854
 9855                for selection in selections.iter() {
 9856                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9857                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9858                    if selection_start.buffer_id != selection_end.buffer_id {
 9859                        continue;
 9860                    }
 9861                    if let Some(ranges) =
 9862                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9863                    {
 9864                        for (buffer, entries) in ranges {
 9865                            linked_ranges.entry(buffer).or_default().extend(entries);
 9866                        }
 9867                    }
 9868                }
 9869            }
 9870
 9871            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9872            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9873            for selection in &mut selections {
 9874                if selection.is_empty() {
 9875                    let old_head = selection.head();
 9876                    let mut new_head =
 9877                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9878                            .to_point(&display_map);
 9879                    if let Some((buffer, line_buffer_range)) = display_map
 9880                        .buffer_snapshot
 9881                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9882                    {
 9883                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9884                        let indent_len = match indent_size.kind {
 9885                            IndentKind::Space => {
 9886                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9887                            }
 9888                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9889                        };
 9890                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9891                            let indent_len = indent_len.get();
 9892                            new_head = cmp::min(
 9893                                new_head,
 9894                                MultiBufferPoint::new(
 9895                                    old_head.row,
 9896                                    ((old_head.column - 1) / indent_len) * indent_len,
 9897                                ),
 9898                            );
 9899                        }
 9900                    }
 9901
 9902                    selection.set_head(new_head, SelectionGoal::None);
 9903                }
 9904            }
 9905
 9906            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9907            this.insert("", window, cx);
 9908            let empty_str: Arc<str> = Arc::from("");
 9909            for (buffer, edits) in linked_ranges {
 9910                let snapshot = buffer.read(cx).snapshot();
 9911                use text::ToPoint as TP;
 9912
 9913                let edits = edits
 9914                    .into_iter()
 9915                    .map(|range| {
 9916                        let end_point = TP::to_point(&range.end, &snapshot);
 9917                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9918
 9919                        if end_point == start_point {
 9920                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9921                                .saturating_sub(1);
 9922                            start_point =
 9923                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9924                        };
 9925
 9926                        (start_point..end_point, empty_str.clone())
 9927                    })
 9928                    .sorted_by_key(|(range, _)| range.start)
 9929                    .collect::<Vec<_>>();
 9930                buffer.update(cx, |this, cx| {
 9931                    this.edit(edits, None, cx);
 9932                })
 9933            }
 9934            this.refresh_edit_prediction(true, false, window, cx);
 9935            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9936        });
 9937    }
 9938
 9939    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9940        if self.read_only(cx) {
 9941            return;
 9942        }
 9943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9944        self.transact(window, cx, |this, window, cx| {
 9945            this.change_selections(Default::default(), window, cx, |s| {
 9946                s.move_with(|map, selection| {
 9947                    if selection.is_empty() {
 9948                        let cursor = movement::right(map, selection.head());
 9949                        selection.end = cursor;
 9950                        selection.reversed = true;
 9951                        selection.goal = SelectionGoal::None;
 9952                    }
 9953                })
 9954            });
 9955            this.insert("", window, cx);
 9956            this.refresh_edit_prediction(true, false, window, cx);
 9957        });
 9958    }
 9959
 9960    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9961        if self.mode.is_single_line() {
 9962            cx.propagate();
 9963            return;
 9964        }
 9965
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        if self.move_to_prev_snippet_tabstop(window, cx) {
 9968            return;
 9969        }
 9970        self.outdent(&Outdent, window, cx);
 9971    }
 9972
 9973    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9974        if self.mode.is_single_line() {
 9975            cx.propagate();
 9976            return;
 9977        }
 9978
 9979        if self.move_to_next_snippet_tabstop(window, cx) {
 9980            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9981            return;
 9982        }
 9983        if self.read_only(cx) {
 9984            return;
 9985        }
 9986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987        let mut selections = self.selections.all_adjusted(cx);
 9988        let buffer = self.buffer.read(cx);
 9989        let snapshot = buffer.snapshot(cx);
 9990        let rows_iter = selections.iter().map(|s| s.head().row);
 9991        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9992
 9993        let has_some_cursor_in_whitespace = selections
 9994            .iter()
 9995            .filter(|selection| selection.is_empty())
 9996            .any(|selection| {
 9997                let cursor = selection.head();
 9998                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9999                cursor.column < current_indent.len
10000            });
10001
10002        let mut edits = Vec::new();
10003        let mut prev_edited_row = 0;
10004        let mut row_delta = 0;
10005        for selection in &mut selections {
10006            if selection.start.row != prev_edited_row {
10007                row_delta = 0;
10008            }
10009            prev_edited_row = selection.end.row;
10010
10011            // If the selection is non-empty, then increase the indentation of the selected lines.
10012            if !selection.is_empty() {
10013                row_delta =
10014                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10015                continue;
10016            }
10017
10018            let cursor = selection.head();
10019            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10020            if let Some(suggested_indent) =
10021                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10022            {
10023                // Don't do anything if already at suggested indent
10024                // and there is any other cursor which is not
10025                if has_some_cursor_in_whitespace
10026                    && cursor.column == current_indent.len
10027                    && current_indent.len == suggested_indent.len
10028                {
10029                    continue;
10030                }
10031
10032                // Adjust line and move cursor to suggested indent
10033                // if cursor is not at suggested indent
10034                if cursor.column < suggested_indent.len
10035                    && cursor.column <= current_indent.len
10036                    && current_indent.len <= suggested_indent.len
10037                {
10038                    selection.start = Point::new(cursor.row, suggested_indent.len);
10039                    selection.end = selection.start;
10040                    if row_delta == 0 {
10041                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10042                            cursor.row,
10043                            current_indent,
10044                            suggested_indent,
10045                        ));
10046                        row_delta = suggested_indent.len - current_indent.len;
10047                    }
10048                    continue;
10049                }
10050
10051                // If current indent is more than suggested indent
10052                // only move cursor to current indent and skip indent
10053                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10054                    selection.start = Point::new(cursor.row, current_indent.len);
10055                    selection.end = selection.start;
10056                    continue;
10057                }
10058            }
10059
10060            // Otherwise, insert a hard or soft tab.
10061            let settings = buffer.language_settings_at(cursor, cx);
10062            let tab_size = if settings.hard_tabs {
10063                IndentSize::tab()
10064            } else {
10065                let tab_size = settings.tab_size.get();
10066                let indent_remainder = snapshot
10067                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10068                    .flat_map(str::chars)
10069                    .fold(row_delta % tab_size, |counter: u32, c| {
10070                        if c == '\t' {
10071                            0
10072                        } else {
10073                            (counter + 1) % tab_size
10074                        }
10075                    });
10076
10077                let chars_to_next_tab_stop = tab_size - indent_remainder;
10078                IndentSize::spaces(chars_to_next_tab_stop)
10079            };
10080            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10081            selection.end = selection.start;
10082            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10083            row_delta += tab_size.len;
10084        }
10085
10086        self.transact(window, cx, |this, window, cx| {
10087            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10088            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10089            this.refresh_edit_prediction(true, false, window, cx);
10090        });
10091    }
10092
10093    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10094        if self.read_only(cx) {
10095            return;
10096        }
10097        if self.mode.is_single_line() {
10098            cx.propagate();
10099            return;
10100        }
10101
10102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10103        let mut selections = self.selections.all::<Point>(cx);
10104        let mut prev_edited_row = 0;
10105        let mut row_delta = 0;
10106        let mut edits = Vec::new();
10107        let buffer = self.buffer.read(cx);
10108        let snapshot = buffer.snapshot(cx);
10109        for selection in &mut selections {
10110            if selection.start.row != prev_edited_row {
10111                row_delta = 0;
10112            }
10113            prev_edited_row = selection.end.row;
10114
10115            row_delta =
10116                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10117        }
10118
10119        self.transact(window, cx, |this, window, cx| {
10120            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10121            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10122        });
10123    }
10124
10125    fn indent_selection(
10126        buffer: &MultiBuffer,
10127        snapshot: &MultiBufferSnapshot,
10128        selection: &mut Selection<Point>,
10129        edits: &mut Vec<(Range<Point>, String)>,
10130        delta_for_start_row: u32,
10131        cx: &App,
10132    ) -> u32 {
10133        let settings = buffer.language_settings_at(selection.start, cx);
10134        let tab_size = settings.tab_size.get();
10135        let indent_kind = if settings.hard_tabs {
10136            IndentKind::Tab
10137        } else {
10138            IndentKind::Space
10139        };
10140        let mut start_row = selection.start.row;
10141        let mut end_row = selection.end.row + 1;
10142
10143        // If a selection ends at the beginning of a line, don't indent
10144        // that last line.
10145        if selection.end.column == 0 && selection.end.row > selection.start.row {
10146            end_row -= 1;
10147        }
10148
10149        // Avoid re-indenting a row that has already been indented by a
10150        // previous selection, but still update this selection's column
10151        // to reflect that indentation.
10152        if delta_for_start_row > 0 {
10153            start_row += 1;
10154            selection.start.column += delta_for_start_row;
10155            if selection.end.row == selection.start.row {
10156                selection.end.column += delta_for_start_row;
10157            }
10158        }
10159
10160        let mut delta_for_end_row = 0;
10161        let has_multiple_rows = start_row + 1 != end_row;
10162        for row in start_row..end_row {
10163            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10164            let indent_delta = match (current_indent.kind, indent_kind) {
10165                (IndentKind::Space, IndentKind::Space) => {
10166                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10167                    IndentSize::spaces(columns_to_next_tab_stop)
10168                }
10169                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10170                (_, IndentKind::Tab) => IndentSize::tab(),
10171            };
10172
10173            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10174                0
10175            } else {
10176                selection.start.column
10177            };
10178            let row_start = Point::new(row, start);
10179            edits.push((
10180                row_start..row_start,
10181                indent_delta.chars().collect::<String>(),
10182            ));
10183
10184            // Update this selection's endpoints to reflect the indentation.
10185            if row == selection.start.row {
10186                selection.start.column += indent_delta.len;
10187            }
10188            if row == selection.end.row {
10189                selection.end.column += indent_delta.len;
10190                delta_for_end_row = indent_delta.len;
10191            }
10192        }
10193
10194        if selection.start.row == selection.end.row {
10195            delta_for_start_row + delta_for_end_row
10196        } else {
10197            delta_for_end_row
10198        }
10199    }
10200
10201    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10202        if self.read_only(cx) {
10203            return;
10204        }
10205        if self.mode.is_single_line() {
10206            cx.propagate();
10207            return;
10208        }
10209
10210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10211        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10212        let selections = self.selections.all::<Point>(cx);
10213        let mut deletion_ranges = Vec::new();
10214        let mut last_outdent = None;
10215        {
10216            let buffer = self.buffer.read(cx);
10217            let snapshot = buffer.snapshot(cx);
10218            for selection in &selections {
10219                let settings = buffer.language_settings_at(selection.start, cx);
10220                let tab_size = settings.tab_size.get();
10221                let mut rows = selection.spanned_rows(false, &display_map);
10222
10223                // Avoid re-outdenting a row that has already been outdented by a
10224                // previous selection.
10225                if let Some(last_row) = last_outdent
10226                    && last_row == rows.start
10227                {
10228                    rows.start = rows.start.next_row();
10229                }
10230                let has_multiple_rows = rows.len() > 1;
10231                for row in rows.iter_rows() {
10232                    let indent_size = snapshot.indent_size_for_line(row);
10233                    if indent_size.len > 0 {
10234                        let deletion_len = match indent_size.kind {
10235                            IndentKind::Space => {
10236                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10237                                if columns_to_prev_tab_stop == 0 {
10238                                    tab_size
10239                                } else {
10240                                    columns_to_prev_tab_stop
10241                                }
10242                            }
10243                            IndentKind::Tab => 1,
10244                        };
10245                        let start = if has_multiple_rows
10246                            || deletion_len > selection.start.column
10247                            || indent_size.len < selection.start.column
10248                        {
10249                            0
10250                        } else {
10251                            selection.start.column - deletion_len
10252                        };
10253                        deletion_ranges.push(
10254                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10255                        );
10256                        last_outdent = Some(row);
10257                    }
10258                }
10259            }
10260        }
10261
10262        self.transact(window, cx, |this, window, cx| {
10263            this.buffer.update(cx, |buffer, cx| {
10264                let empty_str: Arc<str> = Arc::default();
10265                buffer.edit(
10266                    deletion_ranges
10267                        .into_iter()
10268                        .map(|range| (range, empty_str.clone())),
10269                    None,
10270                    cx,
10271                );
10272            });
10273            let selections = this.selections.all::<usize>(cx);
10274            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10275        });
10276    }
10277
10278    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10279        if self.read_only(cx) {
10280            return;
10281        }
10282        if self.mode.is_single_line() {
10283            cx.propagate();
10284            return;
10285        }
10286
10287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10288        let selections = self
10289            .selections
10290            .all::<usize>(cx)
10291            .into_iter()
10292            .map(|s| s.range());
10293
10294        self.transact(window, cx, |this, window, cx| {
10295            this.buffer.update(cx, |buffer, cx| {
10296                buffer.autoindent_ranges(selections, cx);
10297            });
10298            let selections = this.selections.all::<usize>(cx);
10299            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10300        });
10301    }
10302
10303    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10305        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10306        let selections = self.selections.all::<Point>(cx);
10307
10308        let mut new_cursors = Vec::new();
10309        let mut edit_ranges = Vec::new();
10310        let mut selections = selections.iter().peekable();
10311        while let Some(selection) = selections.next() {
10312            let mut rows = selection.spanned_rows(false, &display_map);
10313            let goal_display_column = selection.head().to_display_point(&display_map).column();
10314
10315            // Accumulate contiguous regions of rows that we want to delete.
10316            while let Some(next_selection) = selections.peek() {
10317                let next_rows = next_selection.spanned_rows(false, &display_map);
10318                if next_rows.start <= rows.end {
10319                    rows.end = next_rows.end;
10320                    selections.next().unwrap();
10321                } else {
10322                    break;
10323                }
10324            }
10325
10326            let buffer = &display_map.buffer_snapshot;
10327            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10328            let edit_end;
10329            let cursor_buffer_row;
10330            if buffer.max_point().row >= rows.end.0 {
10331                // If there's a line after the range, delete the \n from the end of the row range
10332                // and position the cursor on the next line.
10333                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10334                cursor_buffer_row = rows.end;
10335            } else {
10336                // If there isn't a line after the range, delete the \n from the line before the
10337                // start of the row range and position the cursor there.
10338                edit_start = edit_start.saturating_sub(1);
10339                edit_end = buffer.len();
10340                cursor_buffer_row = rows.start.previous_row();
10341            }
10342
10343            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10344            *cursor.column_mut() =
10345                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10346
10347            new_cursors.push((
10348                selection.id,
10349                buffer.anchor_after(cursor.to_point(&display_map)),
10350            ));
10351            edit_ranges.push(edit_start..edit_end);
10352        }
10353
10354        self.transact(window, cx, |this, window, cx| {
10355            let buffer = this.buffer.update(cx, |buffer, cx| {
10356                let empty_str: Arc<str> = Arc::default();
10357                buffer.edit(
10358                    edit_ranges
10359                        .into_iter()
10360                        .map(|range| (range, empty_str.clone())),
10361                    None,
10362                    cx,
10363                );
10364                buffer.snapshot(cx)
10365            });
10366            let new_selections = new_cursors
10367                .into_iter()
10368                .map(|(id, cursor)| {
10369                    let cursor = cursor.to_point(&buffer);
10370                    Selection {
10371                        id,
10372                        start: cursor,
10373                        end: cursor,
10374                        reversed: false,
10375                        goal: SelectionGoal::None,
10376                    }
10377                })
10378                .collect();
10379
10380            this.change_selections(Default::default(), window, cx, |s| {
10381                s.select(new_selections);
10382            });
10383        });
10384    }
10385
10386    pub fn join_lines_impl(
10387        &mut self,
10388        insert_whitespace: bool,
10389        window: &mut Window,
10390        cx: &mut Context<Self>,
10391    ) {
10392        if self.read_only(cx) {
10393            return;
10394        }
10395        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10396        for selection in self.selections.all::<Point>(cx) {
10397            let start = MultiBufferRow(selection.start.row);
10398            // Treat single line selections as if they include the next line. Otherwise this action
10399            // would do nothing for single line selections individual cursors.
10400            let end = if selection.start.row == selection.end.row {
10401                MultiBufferRow(selection.start.row + 1)
10402            } else {
10403                MultiBufferRow(selection.end.row)
10404            };
10405
10406            if let Some(last_row_range) = row_ranges.last_mut()
10407                && start <= last_row_range.end
10408            {
10409                last_row_range.end = end;
10410                continue;
10411            }
10412            row_ranges.push(start..end);
10413        }
10414
10415        let snapshot = self.buffer.read(cx).snapshot(cx);
10416        let mut cursor_positions = Vec::new();
10417        for row_range in &row_ranges {
10418            let anchor = snapshot.anchor_before(Point::new(
10419                row_range.end.previous_row().0,
10420                snapshot.line_len(row_range.end.previous_row()),
10421            ));
10422            cursor_positions.push(anchor..anchor);
10423        }
10424
10425        self.transact(window, cx, |this, window, cx| {
10426            for row_range in row_ranges.into_iter().rev() {
10427                for row in row_range.iter_rows().rev() {
10428                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10429                    let next_line_row = row.next_row();
10430                    let indent = snapshot.indent_size_for_line(next_line_row);
10431                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10432
10433                    let replace =
10434                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10435                            " "
10436                        } else {
10437                            ""
10438                        };
10439
10440                    this.buffer.update(cx, |buffer, cx| {
10441                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10442                    });
10443                }
10444            }
10445
10446            this.change_selections(Default::default(), window, cx, |s| {
10447                s.select_anchor_ranges(cursor_positions)
10448            });
10449        });
10450    }
10451
10452    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10454        self.join_lines_impl(true, window, cx);
10455    }
10456
10457    pub fn sort_lines_case_sensitive(
10458        &mut self,
10459        _: &SortLinesCaseSensitive,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10464    }
10465
10466    pub fn sort_lines_by_length(
10467        &mut self,
10468        _: &SortLinesByLength,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.manipulate_immutable_lines(window, cx, |lines| {
10473            lines.sort_by_key(|&line| line.chars().count())
10474        })
10475    }
10476
10477    pub fn sort_lines_case_insensitive(
10478        &mut self,
10479        _: &SortLinesCaseInsensitive,
10480        window: &mut Window,
10481        cx: &mut Context<Self>,
10482    ) {
10483        self.manipulate_immutable_lines(window, cx, |lines| {
10484            lines.sort_by_key(|line| line.to_lowercase())
10485        })
10486    }
10487
10488    pub fn unique_lines_case_insensitive(
10489        &mut self,
10490        _: &UniqueLinesCaseInsensitive,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        self.manipulate_immutable_lines(window, cx, |lines| {
10495            let mut seen = HashSet::default();
10496            lines.retain(|line| seen.insert(line.to_lowercase()));
10497        })
10498    }
10499
10500    pub fn unique_lines_case_sensitive(
10501        &mut self,
10502        _: &UniqueLinesCaseSensitive,
10503        window: &mut Window,
10504        cx: &mut Context<Self>,
10505    ) {
10506        self.manipulate_immutable_lines(window, cx, |lines| {
10507            let mut seen = HashSet::default();
10508            lines.retain(|line| seen.insert(*line));
10509        })
10510    }
10511
10512    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10513        let snapshot = self.buffer.read(cx).snapshot(cx);
10514        for selection in self.selections.disjoint_anchors().iter() {
10515            if snapshot
10516                .language_at(selection.start)
10517                .and_then(|lang| lang.config().wrap_characters.as_ref())
10518                .is_some()
10519            {
10520                return true;
10521            }
10522        }
10523        false
10524    }
10525
10526    fn wrap_selections_in_tag(
10527        &mut self,
10528        _: &WrapSelectionsInTag,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) {
10532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10533
10534        let snapshot = self.buffer.read(cx).snapshot(cx);
10535
10536        let mut edits = Vec::new();
10537        let mut boundaries = Vec::new();
10538
10539        for selection in self.selections.all::<Point>(cx).iter() {
10540            let Some(wrap_config) = snapshot
10541                .language_at(selection.start)
10542                .and_then(|lang| lang.config().wrap_characters.clone())
10543            else {
10544                continue;
10545            };
10546
10547            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10548            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10549
10550            let start_before = snapshot.anchor_before(selection.start);
10551            let end_after = snapshot.anchor_after(selection.end);
10552
10553            edits.push((start_before..start_before, open_tag));
10554            edits.push((end_after..end_after, close_tag));
10555
10556            boundaries.push((
10557                start_before,
10558                end_after,
10559                wrap_config.start_prefix.len(),
10560                wrap_config.end_suffix.len(),
10561            ));
10562        }
10563
10564        if edits.is_empty() {
10565            return;
10566        }
10567
10568        self.transact(window, cx, |this, window, cx| {
10569            let buffer = this.buffer.update(cx, |buffer, cx| {
10570                buffer.edit(edits, None, cx);
10571                buffer.snapshot(cx)
10572            });
10573
10574            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10575            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10576                boundaries.into_iter()
10577            {
10578                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10579                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10580                new_selections.push(open_offset..open_offset);
10581                new_selections.push(close_offset..close_offset);
10582            }
10583
10584            this.change_selections(Default::default(), window, cx, |s| {
10585                s.select_ranges(new_selections);
10586            });
10587
10588            this.request_autoscroll(Autoscroll::fit(), cx);
10589        });
10590    }
10591
10592    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10593        let Some(project) = self.project.clone() else {
10594            return;
10595        };
10596        self.reload(project, window, cx)
10597            .detach_and_notify_err(window, cx);
10598    }
10599
10600    pub fn restore_file(
10601        &mut self,
10602        _: &::git::RestoreFile,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10607        let mut buffer_ids = HashSet::default();
10608        let snapshot = self.buffer().read(cx).snapshot(cx);
10609        for selection in self.selections.all::<usize>(cx) {
10610            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10611        }
10612
10613        let buffer = self.buffer().read(cx);
10614        let ranges = buffer_ids
10615            .into_iter()
10616            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10617            .collect::<Vec<_>>();
10618
10619        self.restore_hunks_in_ranges(ranges, window, cx);
10620    }
10621
10622    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10623        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10624        let selections = self
10625            .selections
10626            .all(cx)
10627            .into_iter()
10628            .map(|s| s.range())
10629            .collect();
10630        self.restore_hunks_in_ranges(selections, window, cx);
10631    }
10632
10633    pub fn restore_hunks_in_ranges(
10634        &mut self,
10635        ranges: Vec<Range<Point>>,
10636        window: &mut Window,
10637        cx: &mut Context<Editor>,
10638    ) {
10639        let mut revert_changes = HashMap::default();
10640        let chunk_by = self
10641            .snapshot(window, cx)
10642            .hunks_for_ranges(ranges)
10643            .into_iter()
10644            .chunk_by(|hunk| hunk.buffer_id);
10645        for (buffer_id, hunks) in &chunk_by {
10646            let hunks = hunks.collect::<Vec<_>>();
10647            for hunk in &hunks {
10648                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10649            }
10650            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10651        }
10652        drop(chunk_by);
10653        if !revert_changes.is_empty() {
10654            self.transact(window, cx, |editor, window, cx| {
10655                editor.restore(revert_changes, window, cx);
10656            });
10657        }
10658    }
10659
10660    pub fn open_active_item_in_terminal(
10661        &mut self,
10662        _: &OpenInTerminal,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10667            let project_path = buffer.read(cx).project_path(cx)?;
10668            let project = self.project()?.read(cx);
10669            let entry = project.entry_for_path(&project_path, cx)?;
10670            let parent = match &entry.canonical_path {
10671                Some(canonical_path) => canonical_path.to_path_buf(),
10672                None => project.absolute_path(&project_path, cx)?,
10673            }
10674            .parent()?
10675            .to_path_buf();
10676            Some(parent)
10677        }) {
10678            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10679        }
10680    }
10681
10682    fn set_breakpoint_context_menu(
10683        &mut self,
10684        display_row: DisplayRow,
10685        position: Option<Anchor>,
10686        clicked_point: gpui::Point<Pixels>,
10687        window: &mut Window,
10688        cx: &mut Context<Self>,
10689    ) {
10690        let source = self
10691            .buffer
10692            .read(cx)
10693            .snapshot(cx)
10694            .anchor_before(Point::new(display_row.0, 0u32));
10695
10696        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10697
10698        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10699            self,
10700            source,
10701            clicked_point,
10702            context_menu,
10703            window,
10704            cx,
10705        );
10706    }
10707
10708    fn add_edit_breakpoint_block(
10709        &mut self,
10710        anchor: Anchor,
10711        breakpoint: &Breakpoint,
10712        edit_action: BreakpointPromptEditAction,
10713        window: &mut Window,
10714        cx: &mut Context<Self>,
10715    ) {
10716        let weak_editor = cx.weak_entity();
10717        let bp_prompt = cx.new(|cx| {
10718            BreakpointPromptEditor::new(
10719                weak_editor,
10720                anchor,
10721                breakpoint.clone(),
10722                edit_action,
10723                window,
10724                cx,
10725            )
10726        });
10727
10728        let height = bp_prompt.update(cx, |this, cx| {
10729            this.prompt
10730                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10731        });
10732        let cloned_prompt = bp_prompt.clone();
10733        let blocks = vec![BlockProperties {
10734            style: BlockStyle::Sticky,
10735            placement: BlockPlacement::Above(anchor),
10736            height: Some(height),
10737            render: Arc::new(move |cx| {
10738                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10739                cloned_prompt.clone().into_any_element()
10740            }),
10741            priority: 0,
10742        }];
10743
10744        let focus_handle = bp_prompt.focus_handle(cx);
10745        window.focus(&focus_handle);
10746
10747        let block_ids = self.insert_blocks(blocks, None, cx);
10748        bp_prompt.update(cx, |prompt, _| {
10749            prompt.add_block_ids(block_ids);
10750        });
10751    }
10752
10753    pub(crate) fn breakpoint_at_row(
10754        &self,
10755        row: u32,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) -> Option<(Anchor, Breakpoint)> {
10759        let snapshot = self.snapshot(window, cx);
10760        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10761
10762        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10763    }
10764
10765    pub(crate) fn breakpoint_at_anchor(
10766        &self,
10767        breakpoint_position: Anchor,
10768        snapshot: &EditorSnapshot,
10769        cx: &mut Context<Self>,
10770    ) -> Option<(Anchor, Breakpoint)> {
10771        let buffer = self
10772            .buffer
10773            .read(cx)
10774            .buffer_for_anchor(breakpoint_position, cx)?;
10775
10776        let enclosing_excerpt = breakpoint_position.excerpt_id;
10777        let buffer_snapshot = buffer.read(cx).snapshot();
10778
10779        let row = buffer_snapshot
10780            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10781            .row;
10782
10783        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10784        let anchor_end = snapshot
10785            .buffer_snapshot
10786            .anchor_after(Point::new(row, line_len));
10787
10788        self.breakpoint_store
10789            .as_ref()?
10790            .read_with(cx, |breakpoint_store, cx| {
10791                breakpoint_store
10792                    .breakpoints(
10793                        &buffer,
10794                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10795                        &buffer_snapshot,
10796                        cx,
10797                    )
10798                    .next()
10799                    .and_then(|(bp, _)| {
10800                        let breakpoint_row = buffer_snapshot
10801                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10802                            .row;
10803
10804                        if breakpoint_row == row {
10805                            snapshot
10806                                .buffer_snapshot
10807                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10808                                .map(|position| (position, bp.bp.clone()))
10809                        } else {
10810                            None
10811                        }
10812                    })
10813            })
10814    }
10815
10816    pub fn edit_log_breakpoint(
10817        &mut self,
10818        _: &EditLogBreakpoint,
10819        window: &mut Window,
10820        cx: &mut Context<Self>,
10821    ) {
10822        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10823            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10824                message: None,
10825                state: BreakpointState::Enabled,
10826                condition: None,
10827                hit_condition: None,
10828            });
10829
10830            self.add_edit_breakpoint_block(
10831                anchor,
10832                &breakpoint,
10833                BreakpointPromptEditAction::Log,
10834                window,
10835                cx,
10836            );
10837        }
10838    }
10839
10840    fn breakpoints_at_cursors(
10841        &self,
10842        window: &mut Window,
10843        cx: &mut Context<Self>,
10844    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10845        let snapshot = self.snapshot(window, cx);
10846        let cursors = self
10847            .selections
10848            .disjoint_anchors()
10849            .iter()
10850            .map(|selection| {
10851                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10852
10853                let breakpoint_position = self
10854                    .breakpoint_at_row(cursor_position.row, window, cx)
10855                    .map(|bp| bp.0)
10856                    .unwrap_or_else(|| {
10857                        snapshot
10858                            .display_snapshot
10859                            .buffer_snapshot
10860                            .anchor_after(Point::new(cursor_position.row, 0))
10861                    });
10862
10863                let breakpoint = self
10864                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10865                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10866
10867                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10868            })
10869            // 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.
10870            .collect::<HashMap<Anchor, _>>();
10871
10872        cursors.into_iter().collect()
10873    }
10874
10875    pub fn enable_breakpoint(
10876        &mut self,
10877        _: &crate::actions::EnableBreakpoint,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880    ) {
10881        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10882            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10883                continue;
10884            };
10885            self.edit_breakpoint_at_anchor(
10886                anchor,
10887                breakpoint,
10888                BreakpointEditAction::InvertState,
10889                cx,
10890            );
10891        }
10892    }
10893
10894    pub fn disable_breakpoint(
10895        &mut self,
10896        _: &crate::actions::DisableBreakpoint,
10897        window: &mut Window,
10898        cx: &mut Context<Self>,
10899    ) {
10900        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10901            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10902                continue;
10903            };
10904            self.edit_breakpoint_at_anchor(
10905                anchor,
10906                breakpoint,
10907                BreakpointEditAction::InvertState,
10908                cx,
10909            );
10910        }
10911    }
10912
10913    pub fn toggle_breakpoint(
10914        &mut self,
10915        _: &crate::actions::ToggleBreakpoint,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918    ) {
10919        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10920            if let Some(breakpoint) = breakpoint {
10921                self.edit_breakpoint_at_anchor(
10922                    anchor,
10923                    breakpoint,
10924                    BreakpointEditAction::Toggle,
10925                    cx,
10926                );
10927            } else {
10928                self.edit_breakpoint_at_anchor(
10929                    anchor,
10930                    Breakpoint::new_standard(),
10931                    BreakpointEditAction::Toggle,
10932                    cx,
10933                );
10934            }
10935        }
10936    }
10937
10938    pub fn edit_breakpoint_at_anchor(
10939        &mut self,
10940        breakpoint_position: Anchor,
10941        breakpoint: Breakpoint,
10942        edit_action: BreakpointEditAction,
10943        cx: &mut Context<Self>,
10944    ) {
10945        let Some(breakpoint_store) = &self.breakpoint_store else {
10946            return;
10947        };
10948
10949        let Some(buffer) = self
10950            .buffer
10951            .read(cx)
10952            .buffer_for_anchor(breakpoint_position, cx)
10953        else {
10954            return;
10955        };
10956
10957        breakpoint_store.update(cx, |breakpoint_store, cx| {
10958            breakpoint_store.toggle_breakpoint(
10959                buffer,
10960                BreakpointWithPosition {
10961                    position: breakpoint_position.text_anchor,
10962                    bp: breakpoint,
10963                },
10964                edit_action,
10965                cx,
10966            );
10967        });
10968
10969        cx.notify();
10970    }
10971
10972    #[cfg(any(test, feature = "test-support"))]
10973    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10974        self.breakpoint_store.clone()
10975    }
10976
10977    pub fn prepare_restore_change(
10978        &self,
10979        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10980        hunk: &MultiBufferDiffHunk,
10981        cx: &mut App,
10982    ) -> Option<()> {
10983        if hunk.is_created_file() {
10984            return None;
10985        }
10986        let buffer = self.buffer.read(cx);
10987        let diff = buffer.diff_for(hunk.buffer_id)?;
10988        let buffer = buffer.buffer(hunk.buffer_id)?;
10989        let buffer = buffer.read(cx);
10990        let original_text = diff
10991            .read(cx)
10992            .base_text()
10993            .as_rope()
10994            .slice(hunk.diff_base_byte_range.clone());
10995        let buffer_snapshot = buffer.snapshot();
10996        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10997        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10998            probe
10999                .0
11000                .start
11001                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11002                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11003        }) {
11004            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11005            Some(())
11006        } else {
11007            None
11008        }
11009    }
11010
11011    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11012        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11013    }
11014
11015    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11016        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11017    }
11018
11019    fn manipulate_lines<M>(
11020        &mut self,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023        mut manipulate: M,
11024    ) where
11025        M: FnMut(&str) -> LineManipulationResult,
11026    {
11027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11028
11029        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11030        let buffer = self.buffer.read(cx).snapshot(cx);
11031
11032        let mut edits = Vec::new();
11033
11034        let selections = self.selections.all::<Point>(cx);
11035        let mut selections = selections.iter().peekable();
11036        let mut contiguous_row_selections = Vec::new();
11037        let mut new_selections = Vec::new();
11038        let mut added_lines = 0;
11039        let mut removed_lines = 0;
11040
11041        while let Some(selection) = selections.next() {
11042            let (start_row, end_row) = consume_contiguous_rows(
11043                &mut contiguous_row_selections,
11044                selection,
11045                &display_map,
11046                &mut selections,
11047            );
11048
11049            let start_point = Point::new(start_row.0, 0);
11050            let end_point = Point::new(
11051                end_row.previous_row().0,
11052                buffer.line_len(end_row.previous_row()),
11053            );
11054            let text = buffer
11055                .text_for_range(start_point..end_point)
11056                .collect::<String>();
11057
11058            let LineManipulationResult {
11059                new_text,
11060                line_count_before,
11061                line_count_after,
11062            } = manipulate(&text);
11063
11064            edits.push((start_point..end_point, new_text));
11065
11066            // Selections must change based on added and removed line count
11067            let start_row =
11068                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11069            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11070            new_selections.push(Selection {
11071                id: selection.id,
11072                start: start_row,
11073                end: end_row,
11074                goal: SelectionGoal::None,
11075                reversed: selection.reversed,
11076            });
11077
11078            if line_count_after > line_count_before {
11079                added_lines += line_count_after - line_count_before;
11080            } else if line_count_before > line_count_after {
11081                removed_lines += line_count_before - line_count_after;
11082            }
11083        }
11084
11085        self.transact(window, cx, |this, window, cx| {
11086            let buffer = this.buffer.update(cx, |buffer, cx| {
11087                buffer.edit(edits, None, cx);
11088                buffer.snapshot(cx)
11089            });
11090
11091            // Recalculate offsets on newly edited buffer
11092            let new_selections = new_selections
11093                .iter()
11094                .map(|s| {
11095                    let start_point = Point::new(s.start.0, 0);
11096                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11097                    Selection {
11098                        id: s.id,
11099                        start: buffer.point_to_offset(start_point),
11100                        end: buffer.point_to_offset(end_point),
11101                        goal: s.goal,
11102                        reversed: s.reversed,
11103                    }
11104                })
11105                .collect();
11106
11107            this.change_selections(Default::default(), window, cx, |s| {
11108                s.select(new_selections);
11109            });
11110
11111            this.request_autoscroll(Autoscroll::fit(), cx);
11112        });
11113    }
11114
11115    fn manipulate_immutable_lines<Fn>(
11116        &mut self,
11117        window: &mut Window,
11118        cx: &mut Context<Self>,
11119        mut callback: Fn,
11120    ) where
11121        Fn: FnMut(&mut Vec<&str>),
11122    {
11123        self.manipulate_lines(window, cx, |text| {
11124            let mut lines: Vec<&str> = text.split('\n').collect();
11125            let line_count_before = lines.len();
11126
11127            callback(&mut lines);
11128
11129            LineManipulationResult {
11130                new_text: lines.join("\n"),
11131                line_count_before,
11132                line_count_after: lines.len(),
11133            }
11134        });
11135    }
11136
11137    fn manipulate_mutable_lines<Fn>(
11138        &mut self,
11139        window: &mut Window,
11140        cx: &mut Context<Self>,
11141        mut callback: Fn,
11142    ) where
11143        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11144    {
11145        self.manipulate_lines(window, cx, |text| {
11146            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11147            let line_count_before = lines.len();
11148
11149            callback(&mut lines);
11150
11151            LineManipulationResult {
11152                new_text: lines.join("\n"),
11153                line_count_before,
11154                line_count_after: lines.len(),
11155            }
11156        });
11157    }
11158
11159    pub fn convert_indentation_to_spaces(
11160        &mut self,
11161        _: &ConvertIndentationToSpaces,
11162        window: &mut Window,
11163        cx: &mut Context<Self>,
11164    ) {
11165        let settings = self.buffer.read(cx).language_settings(cx);
11166        let tab_size = settings.tab_size.get() as usize;
11167
11168        self.manipulate_mutable_lines(window, cx, |lines| {
11169            // Allocates a reasonably sized scratch buffer once for the whole loop
11170            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11171            // Avoids recomputing spaces that could be inserted many times
11172            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11173                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11174                .collect();
11175
11176            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11177                let mut chars = line.as_ref().chars();
11178                let mut col = 0;
11179                let mut changed = false;
11180
11181                for ch in chars.by_ref() {
11182                    match ch {
11183                        ' ' => {
11184                            reindented_line.push(' ');
11185                            col += 1;
11186                        }
11187                        '\t' => {
11188                            // \t are converted to spaces depending on the current column
11189                            let spaces_len = tab_size - (col % tab_size);
11190                            reindented_line.extend(&space_cache[spaces_len - 1]);
11191                            col += spaces_len;
11192                            changed = true;
11193                        }
11194                        _ => {
11195                            // If we dont append before break, the character is consumed
11196                            reindented_line.push(ch);
11197                            break;
11198                        }
11199                    }
11200                }
11201
11202                if !changed {
11203                    reindented_line.clear();
11204                    continue;
11205                }
11206                // Append the rest of the line and replace old reference with new one
11207                reindented_line.extend(chars);
11208                *line = Cow::Owned(reindented_line.clone());
11209                reindented_line.clear();
11210            }
11211        });
11212    }
11213
11214    pub fn convert_indentation_to_tabs(
11215        &mut self,
11216        _: &ConvertIndentationToTabs,
11217        window: &mut Window,
11218        cx: &mut Context<Self>,
11219    ) {
11220        let settings = self.buffer.read(cx).language_settings(cx);
11221        let tab_size = settings.tab_size.get() as usize;
11222
11223        self.manipulate_mutable_lines(window, cx, |lines| {
11224            // Allocates a reasonably sized buffer once for the whole loop
11225            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11226            // Avoids recomputing spaces that could be inserted many times
11227            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11228                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11229                .collect();
11230
11231            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11232                let mut chars = line.chars();
11233                let mut spaces_count = 0;
11234                let mut first_non_indent_char = None;
11235                let mut changed = false;
11236
11237                for ch in chars.by_ref() {
11238                    match ch {
11239                        ' ' => {
11240                            // Keep track of spaces. Append \t when we reach tab_size
11241                            spaces_count += 1;
11242                            changed = true;
11243                            if spaces_count == tab_size {
11244                                reindented_line.push('\t');
11245                                spaces_count = 0;
11246                            }
11247                        }
11248                        '\t' => {
11249                            reindented_line.push('\t');
11250                            spaces_count = 0;
11251                        }
11252                        _ => {
11253                            // Dont append it yet, we might have remaining spaces
11254                            first_non_indent_char = Some(ch);
11255                            break;
11256                        }
11257                    }
11258                }
11259
11260                if !changed {
11261                    reindented_line.clear();
11262                    continue;
11263                }
11264                // Remaining spaces that didn't make a full tab stop
11265                if spaces_count > 0 {
11266                    reindented_line.extend(&space_cache[spaces_count - 1]);
11267                }
11268                // If we consume an extra character that was not indentation, add it back
11269                if let Some(extra_char) = first_non_indent_char {
11270                    reindented_line.push(extra_char);
11271                }
11272                // Append the rest of the line and replace old reference with new one
11273                reindented_line.extend(chars);
11274                *line = Cow::Owned(reindented_line.clone());
11275                reindented_line.clear();
11276            }
11277        });
11278    }
11279
11280    pub fn convert_to_upper_case(
11281        &mut self,
11282        _: &ConvertToUpperCase,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        self.manipulate_text(window, cx, |text| text.to_uppercase())
11287    }
11288
11289    pub fn convert_to_lower_case(
11290        &mut self,
11291        _: &ConvertToLowerCase,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.manipulate_text(window, cx, |text| text.to_lowercase())
11296    }
11297
11298    pub fn convert_to_title_case(
11299        &mut self,
11300        _: &ConvertToTitleCase,
11301        window: &mut Window,
11302        cx: &mut Context<Self>,
11303    ) {
11304        self.manipulate_text(window, cx, |text| {
11305            text.split('\n')
11306                .map(|line| line.to_case(Case::Title))
11307                .join("\n")
11308        })
11309    }
11310
11311    pub fn convert_to_snake_case(
11312        &mut self,
11313        _: &ConvertToSnakeCase,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11318    }
11319
11320    pub fn convert_to_kebab_case(
11321        &mut self,
11322        _: &ConvertToKebabCase,
11323        window: &mut Window,
11324        cx: &mut Context<Self>,
11325    ) {
11326        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11327    }
11328
11329    pub fn convert_to_upper_camel_case(
11330        &mut self,
11331        _: &ConvertToUpperCamelCase,
11332        window: &mut Window,
11333        cx: &mut Context<Self>,
11334    ) {
11335        self.manipulate_text(window, cx, |text| {
11336            text.split('\n')
11337                .map(|line| line.to_case(Case::UpperCamel))
11338                .join("\n")
11339        })
11340    }
11341
11342    pub fn convert_to_lower_camel_case(
11343        &mut self,
11344        _: &ConvertToLowerCamelCase,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) {
11348        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11349    }
11350
11351    pub fn convert_to_opposite_case(
11352        &mut self,
11353        _: &ConvertToOppositeCase,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        self.manipulate_text(window, cx, |text| {
11358            text.chars()
11359                .fold(String::with_capacity(text.len()), |mut t, c| {
11360                    if c.is_uppercase() {
11361                        t.extend(c.to_lowercase());
11362                    } else {
11363                        t.extend(c.to_uppercase());
11364                    }
11365                    t
11366                })
11367        })
11368    }
11369
11370    pub fn convert_to_sentence_case(
11371        &mut self,
11372        _: &ConvertToSentenceCase,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11377    }
11378
11379    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11380        self.manipulate_text(window, cx, |text| {
11381            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11382            if has_upper_case_characters {
11383                text.to_lowercase()
11384            } else {
11385                text.to_uppercase()
11386            }
11387        })
11388    }
11389
11390    pub fn convert_to_rot13(
11391        &mut self,
11392        _: &ConvertToRot13,
11393        window: &mut Window,
11394        cx: &mut Context<Self>,
11395    ) {
11396        self.manipulate_text(window, cx, |text| {
11397            text.chars()
11398                .map(|c| match c {
11399                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11400                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11401                    _ => c,
11402                })
11403                .collect()
11404        })
11405    }
11406
11407    pub fn convert_to_rot47(
11408        &mut self,
11409        _: &ConvertToRot47,
11410        window: &mut Window,
11411        cx: &mut Context<Self>,
11412    ) {
11413        self.manipulate_text(window, cx, |text| {
11414            text.chars()
11415                .map(|c| {
11416                    let code_point = c as u32;
11417                    if code_point >= 33 && code_point <= 126 {
11418                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11419                    }
11420                    c
11421                })
11422                .collect()
11423        })
11424    }
11425
11426    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11427    where
11428        Fn: FnMut(&str) -> String,
11429    {
11430        let buffer = self.buffer.read(cx).snapshot(cx);
11431
11432        let mut new_selections = Vec::new();
11433        let mut edits = Vec::new();
11434        let mut selection_adjustment = 0i32;
11435
11436        for selection in self.selections.all_adjusted(cx) {
11437            let selection_is_empty = selection.is_empty();
11438
11439            let (start, end) = if selection_is_empty {
11440                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11441                (word_range.start, word_range.end)
11442            } else {
11443                (
11444                    buffer.point_to_offset(selection.start),
11445                    buffer.point_to_offset(selection.end),
11446                )
11447            };
11448
11449            let text = buffer.text_for_range(start..end).collect::<String>();
11450            let old_length = text.len() as i32;
11451            let text = callback(&text);
11452
11453            new_selections.push(Selection {
11454                start: (start as i32 - selection_adjustment) as usize,
11455                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11456                goal: SelectionGoal::None,
11457                id: selection.id,
11458                reversed: selection.reversed,
11459            });
11460
11461            selection_adjustment += old_length - text.len() as i32;
11462
11463            edits.push((start..end, text));
11464        }
11465
11466        self.transact(window, cx, |this, window, cx| {
11467            this.buffer.update(cx, |buffer, cx| {
11468                buffer.edit(edits, None, cx);
11469            });
11470
11471            this.change_selections(Default::default(), window, cx, |s| {
11472                s.select(new_selections);
11473            });
11474
11475            this.request_autoscroll(Autoscroll::fit(), cx);
11476        });
11477    }
11478
11479    pub fn move_selection_on_drop(
11480        &mut self,
11481        selection: &Selection<Anchor>,
11482        target: DisplayPoint,
11483        is_cut: bool,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11488        let buffer = &display_map.buffer_snapshot;
11489        let mut edits = Vec::new();
11490        let insert_point = display_map
11491            .clip_point(target, Bias::Left)
11492            .to_point(&display_map);
11493        let text = buffer
11494            .text_for_range(selection.start..selection.end)
11495            .collect::<String>();
11496        if is_cut {
11497            edits.push(((selection.start..selection.end), String::new()));
11498        }
11499        let insert_anchor = buffer.anchor_before(insert_point);
11500        edits.push(((insert_anchor..insert_anchor), text));
11501        let last_edit_start = insert_anchor.bias_left(buffer);
11502        let last_edit_end = insert_anchor.bias_right(buffer);
11503        self.transact(window, cx, |this, window, cx| {
11504            this.buffer.update(cx, |buffer, cx| {
11505                buffer.edit(edits, None, cx);
11506            });
11507            this.change_selections(Default::default(), window, cx, |s| {
11508                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11509            });
11510        });
11511    }
11512
11513    pub fn clear_selection_drag_state(&mut self) {
11514        self.selection_drag_state = SelectionDragState::None;
11515    }
11516
11517    pub fn duplicate(
11518        &mut self,
11519        upwards: bool,
11520        whole_lines: bool,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523    ) {
11524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11525
11526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11527        let buffer = &display_map.buffer_snapshot;
11528        let selections = self.selections.all::<Point>(cx);
11529
11530        let mut edits = Vec::new();
11531        let mut selections_iter = selections.iter().peekable();
11532        while let Some(selection) = selections_iter.next() {
11533            let mut rows = selection.spanned_rows(false, &display_map);
11534            // duplicate line-wise
11535            if whole_lines || selection.start == selection.end {
11536                // Avoid duplicating the same lines twice.
11537                while let Some(next_selection) = selections_iter.peek() {
11538                    let next_rows = next_selection.spanned_rows(false, &display_map);
11539                    if next_rows.start < rows.end {
11540                        rows.end = next_rows.end;
11541                        selections_iter.next().unwrap();
11542                    } else {
11543                        break;
11544                    }
11545                }
11546
11547                // Copy the text from the selected row region and splice it either at the start
11548                // or end of the region.
11549                let start = Point::new(rows.start.0, 0);
11550                let end = Point::new(
11551                    rows.end.previous_row().0,
11552                    buffer.line_len(rows.end.previous_row()),
11553                );
11554                let text = buffer
11555                    .text_for_range(start..end)
11556                    .chain(Some("\n"))
11557                    .collect::<String>();
11558                let insert_location = if upwards {
11559                    Point::new(rows.end.0, 0)
11560                } else {
11561                    start
11562                };
11563                edits.push((insert_location..insert_location, text));
11564            } else {
11565                // duplicate character-wise
11566                let start = selection.start;
11567                let end = selection.end;
11568                let text = buffer.text_for_range(start..end).collect::<String>();
11569                edits.push((selection.end..selection.end, text));
11570            }
11571        }
11572
11573        self.transact(window, cx, |this, _, cx| {
11574            this.buffer.update(cx, |buffer, cx| {
11575                buffer.edit(edits, None, cx);
11576            });
11577
11578            this.request_autoscroll(Autoscroll::fit(), cx);
11579        });
11580    }
11581
11582    pub fn duplicate_line_up(
11583        &mut self,
11584        _: &DuplicateLineUp,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.duplicate(true, true, window, cx);
11589    }
11590
11591    pub fn duplicate_line_down(
11592        &mut self,
11593        _: &DuplicateLineDown,
11594        window: &mut Window,
11595        cx: &mut Context<Self>,
11596    ) {
11597        self.duplicate(false, true, window, cx);
11598    }
11599
11600    pub fn duplicate_selection(
11601        &mut self,
11602        _: &DuplicateSelection,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        self.duplicate(false, false, window, cx);
11607    }
11608
11609    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11611        if self.mode.is_single_line() {
11612            cx.propagate();
11613            return;
11614        }
11615
11616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11617        let buffer = self.buffer.read(cx).snapshot(cx);
11618
11619        let mut edits = Vec::new();
11620        let mut unfold_ranges = Vec::new();
11621        let mut refold_creases = Vec::new();
11622
11623        let selections = self.selections.all::<Point>(cx);
11624        let mut selections = selections.iter().peekable();
11625        let mut contiguous_row_selections = Vec::new();
11626        let mut new_selections = Vec::new();
11627
11628        while let Some(selection) = selections.next() {
11629            // Find all the selections that span a contiguous row range
11630            let (start_row, end_row) = consume_contiguous_rows(
11631                &mut contiguous_row_selections,
11632                selection,
11633                &display_map,
11634                &mut selections,
11635            );
11636
11637            // Move the text spanned by the row range to be before the line preceding the row range
11638            if start_row.0 > 0 {
11639                let range_to_move = Point::new(
11640                    start_row.previous_row().0,
11641                    buffer.line_len(start_row.previous_row()),
11642                )
11643                    ..Point::new(
11644                        end_row.previous_row().0,
11645                        buffer.line_len(end_row.previous_row()),
11646                    );
11647                let insertion_point = display_map
11648                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11649                    .0;
11650
11651                // Don't move lines across excerpts
11652                if buffer
11653                    .excerpt_containing(insertion_point..range_to_move.end)
11654                    .is_some()
11655                {
11656                    let text = buffer
11657                        .text_for_range(range_to_move.clone())
11658                        .flat_map(|s| s.chars())
11659                        .skip(1)
11660                        .chain(['\n'])
11661                        .collect::<String>();
11662
11663                    edits.push((
11664                        buffer.anchor_after(range_to_move.start)
11665                            ..buffer.anchor_before(range_to_move.end),
11666                        String::new(),
11667                    ));
11668                    let insertion_anchor = buffer.anchor_after(insertion_point);
11669                    edits.push((insertion_anchor..insertion_anchor, text));
11670
11671                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11672
11673                    // Move selections up
11674                    new_selections.extend(contiguous_row_selections.drain(..).map(
11675                        |mut selection| {
11676                            selection.start.row -= row_delta;
11677                            selection.end.row -= row_delta;
11678                            selection
11679                        },
11680                    ));
11681
11682                    // Move folds up
11683                    unfold_ranges.push(range_to_move.clone());
11684                    for fold in display_map.folds_in_range(
11685                        buffer.anchor_before(range_to_move.start)
11686                            ..buffer.anchor_after(range_to_move.end),
11687                    ) {
11688                        let mut start = fold.range.start.to_point(&buffer);
11689                        let mut end = fold.range.end.to_point(&buffer);
11690                        start.row -= row_delta;
11691                        end.row -= row_delta;
11692                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11693                    }
11694                }
11695            }
11696
11697            // If we didn't move line(s), preserve the existing selections
11698            new_selections.append(&mut contiguous_row_selections);
11699        }
11700
11701        self.transact(window, cx, |this, window, cx| {
11702            this.unfold_ranges(&unfold_ranges, true, true, cx);
11703            this.buffer.update(cx, |buffer, cx| {
11704                for (range, text) in edits {
11705                    buffer.edit([(range, text)], None, cx);
11706                }
11707            });
11708            this.fold_creases(refold_creases, true, window, cx);
11709            this.change_selections(Default::default(), window, cx, |s| {
11710                s.select(new_selections);
11711            })
11712        });
11713    }
11714
11715    pub fn move_line_down(
11716        &mut self,
11717        _: &MoveLineDown,
11718        window: &mut Window,
11719        cx: &mut Context<Self>,
11720    ) {
11721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11722        if self.mode.is_single_line() {
11723            cx.propagate();
11724            return;
11725        }
11726
11727        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11728        let buffer = self.buffer.read(cx).snapshot(cx);
11729
11730        let mut edits = Vec::new();
11731        let mut unfold_ranges = Vec::new();
11732        let mut refold_creases = Vec::new();
11733
11734        let selections = self.selections.all::<Point>(cx);
11735        let mut selections = selections.iter().peekable();
11736        let mut contiguous_row_selections = Vec::new();
11737        let mut new_selections = Vec::new();
11738
11739        while let Some(selection) = selections.next() {
11740            // Find all the selections that span a contiguous row range
11741            let (start_row, end_row) = consume_contiguous_rows(
11742                &mut contiguous_row_selections,
11743                selection,
11744                &display_map,
11745                &mut selections,
11746            );
11747
11748            // Move the text spanned by the row range to be after the last line of the row range
11749            if end_row.0 <= buffer.max_point().row {
11750                let range_to_move =
11751                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11752                let insertion_point = display_map
11753                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11754                    .0;
11755
11756                // Don't move lines across excerpt boundaries
11757                if buffer
11758                    .excerpt_containing(range_to_move.start..insertion_point)
11759                    .is_some()
11760                {
11761                    let mut text = String::from("\n");
11762                    text.extend(buffer.text_for_range(range_to_move.clone()));
11763                    text.pop(); // Drop trailing newline
11764                    edits.push((
11765                        buffer.anchor_after(range_to_move.start)
11766                            ..buffer.anchor_before(range_to_move.end),
11767                        String::new(),
11768                    ));
11769                    let insertion_anchor = buffer.anchor_after(insertion_point);
11770                    edits.push((insertion_anchor..insertion_anchor, text));
11771
11772                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11773
11774                    // Move selections down
11775                    new_selections.extend(contiguous_row_selections.drain(..).map(
11776                        |mut selection| {
11777                            selection.start.row += row_delta;
11778                            selection.end.row += row_delta;
11779                            selection
11780                        },
11781                    ));
11782
11783                    // Move folds down
11784                    unfold_ranges.push(range_to_move.clone());
11785                    for fold in display_map.folds_in_range(
11786                        buffer.anchor_before(range_to_move.start)
11787                            ..buffer.anchor_after(range_to_move.end),
11788                    ) {
11789                        let mut start = fold.range.start.to_point(&buffer);
11790                        let mut end = fold.range.end.to_point(&buffer);
11791                        start.row += row_delta;
11792                        end.row += row_delta;
11793                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11794                    }
11795                }
11796            }
11797
11798            // If we didn't move line(s), preserve the existing selections
11799            new_selections.append(&mut contiguous_row_selections);
11800        }
11801
11802        self.transact(window, cx, |this, window, cx| {
11803            this.unfold_ranges(&unfold_ranges, true, true, cx);
11804            this.buffer.update(cx, |buffer, cx| {
11805                for (range, text) in edits {
11806                    buffer.edit([(range, text)], None, cx);
11807                }
11808            });
11809            this.fold_creases(refold_creases, true, window, cx);
11810            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11811        });
11812    }
11813
11814    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11816        let text_layout_details = &self.text_layout_details(window);
11817        self.transact(window, cx, |this, window, cx| {
11818            let edits = this.change_selections(Default::default(), window, cx, |s| {
11819                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11820                s.move_with(|display_map, selection| {
11821                    if !selection.is_empty() {
11822                        return;
11823                    }
11824
11825                    let mut head = selection.head();
11826                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11827                    if head.column() == display_map.line_len(head.row()) {
11828                        transpose_offset = display_map
11829                            .buffer_snapshot
11830                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11831                    }
11832
11833                    if transpose_offset == 0 {
11834                        return;
11835                    }
11836
11837                    *head.column_mut() += 1;
11838                    head = display_map.clip_point(head, Bias::Right);
11839                    let goal = SelectionGoal::HorizontalPosition(
11840                        display_map
11841                            .x_for_display_point(head, text_layout_details)
11842                            .into(),
11843                    );
11844                    selection.collapse_to(head, goal);
11845
11846                    let transpose_start = display_map
11847                        .buffer_snapshot
11848                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11849                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11850                        let transpose_end = display_map
11851                            .buffer_snapshot
11852                            .clip_offset(transpose_offset + 1, Bias::Right);
11853                        if let Some(ch) =
11854                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11855                        {
11856                            edits.push((transpose_start..transpose_offset, String::new()));
11857                            edits.push((transpose_end..transpose_end, ch.to_string()));
11858                        }
11859                    }
11860                });
11861                edits
11862            });
11863            this.buffer
11864                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11865            let selections = this.selections.all::<usize>(cx);
11866            this.change_selections(Default::default(), window, cx, |s| {
11867                s.select(selections);
11868            });
11869        });
11870    }
11871
11872    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11874        if self.mode.is_single_line() {
11875            cx.propagate();
11876            return;
11877        }
11878
11879        self.rewrap_impl(RewrapOptions::default(), cx)
11880    }
11881
11882    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11883        let buffer = self.buffer.read(cx).snapshot(cx);
11884        let selections = self.selections.all::<Point>(cx);
11885
11886        #[derive(Clone, Debug, PartialEq)]
11887        enum CommentFormat {
11888            /// single line comment, with prefix for line
11889            Line(String),
11890            /// single line within a block comment, with prefix for line
11891            BlockLine(String),
11892            /// a single line of a block comment that includes the initial delimiter
11893            BlockCommentWithStart(BlockCommentConfig),
11894            /// a single line of a block comment that includes the ending delimiter
11895            BlockCommentWithEnd(BlockCommentConfig),
11896        }
11897
11898        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11899        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11900            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11901                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11902                .peekable();
11903
11904            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11905                row
11906            } else {
11907                return Vec::new();
11908            };
11909
11910            let language_settings = buffer.language_settings_at(selection.head(), cx);
11911            let language_scope = buffer.language_scope_at(selection.head());
11912
11913            let indent_and_prefix_for_row =
11914                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11915                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11916                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11917                        &language_scope
11918                    {
11919                        let indent_end = Point::new(row, indent.len);
11920                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11921                        let line_text_after_indent = buffer
11922                            .text_for_range(indent_end..line_end)
11923                            .collect::<String>();
11924
11925                        let is_within_comment_override = buffer
11926                            .language_scope_at(indent_end)
11927                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11928                        let comment_delimiters = if is_within_comment_override {
11929                            // we are within a comment syntax node, but we don't
11930                            // yet know what kind of comment: block, doc or line
11931                            match (
11932                                language_scope.documentation_comment(),
11933                                language_scope.block_comment(),
11934                            ) {
11935                                (Some(config), _) | (_, Some(config))
11936                                    if buffer.contains_str_at(indent_end, &config.start) =>
11937                                {
11938                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11939                                }
11940                                (Some(config), _) | (_, Some(config))
11941                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11947                                {
11948                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11949                                }
11950                                (_, _) => language_scope
11951                                    .line_comment_prefixes()
11952                                    .iter()
11953                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11954                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11955                            }
11956                        } else {
11957                            // we not in an overridden comment node, but we may
11958                            // be within a non-overridden line comment node
11959                            language_scope
11960                                .line_comment_prefixes()
11961                                .iter()
11962                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11963                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11964                        };
11965
11966                        let rewrap_prefix = language_scope
11967                            .rewrap_prefixes()
11968                            .iter()
11969                            .find_map(|prefix_regex| {
11970                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11971                                    if mat.start() == 0 {
11972                                        Some(mat.as_str().to_string())
11973                                    } else {
11974                                        None
11975                                    }
11976                                })
11977                            })
11978                            .flatten();
11979                        (comment_delimiters, rewrap_prefix)
11980                    } else {
11981                        (None, None)
11982                    };
11983                    (indent, comment_prefix, rewrap_prefix)
11984                };
11985
11986            let mut ranges = Vec::new();
11987            let from_empty_selection = selection.is_empty();
11988
11989            let mut current_range_start = first_row;
11990            let mut prev_row = first_row;
11991            let (
11992                mut current_range_indent,
11993                mut current_range_comment_delimiters,
11994                mut current_range_rewrap_prefix,
11995            ) = indent_and_prefix_for_row(first_row);
11996
11997            for row in non_blank_rows_iter.skip(1) {
11998                let has_paragraph_break = row > prev_row + 1;
11999
12000                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12001                    indent_and_prefix_for_row(row);
12002
12003                let has_indent_change = row_indent != current_range_indent;
12004                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12005
12006                let has_boundary_change = has_comment_change
12007                    || row_rewrap_prefix.is_some()
12008                    || (has_indent_change && current_range_comment_delimiters.is_some());
12009
12010                if has_paragraph_break || has_boundary_change {
12011                    ranges.push((
12012                        language_settings.clone(),
12013                        Point::new(current_range_start, 0)
12014                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12015                        current_range_indent,
12016                        current_range_comment_delimiters.clone(),
12017                        current_range_rewrap_prefix.clone(),
12018                        from_empty_selection,
12019                    ));
12020                    current_range_start = row;
12021                    current_range_indent = row_indent;
12022                    current_range_comment_delimiters = row_comment_delimiters;
12023                    current_range_rewrap_prefix = row_rewrap_prefix;
12024                }
12025                prev_row = row;
12026            }
12027
12028            ranges.push((
12029                language_settings.clone(),
12030                Point::new(current_range_start, 0)
12031                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12032                current_range_indent,
12033                current_range_comment_delimiters,
12034                current_range_rewrap_prefix,
12035                from_empty_selection,
12036            ));
12037
12038            ranges
12039        });
12040
12041        let mut edits = Vec::new();
12042        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12043
12044        for (
12045            language_settings,
12046            wrap_range,
12047            mut indent_size,
12048            comment_prefix,
12049            rewrap_prefix,
12050            from_empty_selection,
12051        ) in wrap_ranges
12052        {
12053            let mut start_row = wrap_range.start.row;
12054            let mut end_row = wrap_range.end.row;
12055
12056            // Skip selections that overlap with a range that has already been rewrapped.
12057            let selection_range = start_row..end_row;
12058            if rewrapped_row_ranges
12059                .iter()
12060                .any(|range| range.overlaps(&selection_range))
12061            {
12062                continue;
12063            }
12064
12065            let tab_size = language_settings.tab_size;
12066
12067            let (line_prefix, inside_comment) = match &comment_prefix {
12068                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12069                    (Some(prefix.as_str()), true)
12070                }
12071                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12072                    (Some(prefix.as_ref()), true)
12073                }
12074                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12075                    start: _,
12076                    end: _,
12077                    prefix,
12078                    tab_size,
12079                })) => {
12080                    indent_size.len += tab_size;
12081                    (Some(prefix.as_ref()), true)
12082                }
12083                None => (None, false),
12084            };
12085            let indent_prefix = indent_size.chars().collect::<String>();
12086            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12087
12088            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12089                RewrapBehavior::InComments => inside_comment,
12090                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12091                RewrapBehavior::Anywhere => true,
12092            };
12093
12094            let should_rewrap = options.override_language_settings
12095                || allow_rewrap_based_on_language
12096                || self.hard_wrap.is_some();
12097            if !should_rewrap {
12098                continue;
12099            }
12100
12101            if from_empty_selection {
12102                'expand_upwards: while start_row > 0 {
12103                    let prev_row = start_row - 1;
12104                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12105                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12106                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12107                    {
12108                        start_row = prev_row;
12109                    } else {
12110                        break 'expand_upwards;
12111                    }
12112                }
12113
12114                'expand_downwards: while end_row < buffer.max_point().row {
12115                    let next_row = end_row + 1;
12116                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12117                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12118                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12119                    {
12120                        end_row = next_row;
12121                    } else {
12122                        break 'expand_downwards;
12123                    }
12124                }
12125            }
12126
12127            let start = Point::new(start_row, 0);
12128            let start_offset = start.to_offset(&buffer);
12129            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12130            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12131            let mut first_line_delimiter = None;
12132            let mut last_line_delimiter = None;
12133            let Some(lines_without_prefixes) = selection_text
12134                .lines()
12135                .enumerate()
12136                .map(|(ix, line)| {
12137                    let line_trimmed = line.trim_start();
12138                    if rewrap_prefix.is_some() && ix > 0 {
12139                        Ok(line_trimmed)
12140                    } else if let Some(
12141                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12142                            start,
12143                            prefix,
12144                            end,
12145                            tab_size,
12146                        })
12147                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12148                            start,
12149                            prefix,
12150                            end,
12151                            tab_size,
12152                        }),
12153                    ) = &comment_prefix
12154                    {
12155                        let line_trimmed = line_trimmed
12156                            .strip_prefix(start.as_ref())
12157                            .map(|s| {
12158                                let mut indent_size = indent_size;
12159                                indent_size.len -= tab_size;
12160                                let indent_prefix: String = indent_size.chars().collect();
12161                                first_line_delimiter = Some((indent_prefix, start));
12162                                s.trim_start()
12163                            })
12164                            .unwrap_or(line_trimmed);
12165                        let line_trimmed = line_trimmed
12166                            .strip_suffix(end.as_ref())
12167                            .map(|s| {
12168                                last_line_delimiter = Some(end);
12169                                s.trim_end()
12170                            })
12171                            .unwrap_or(line_trimmed);
12172                        let line_trimmed = line_trimmed
12173                            .strip_prefix(prefix.as_ref())
12174                            .unwrap_or(line_trimmed);
12175                        Ok(line_trimmed)
12176                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12177                        line_trimmed.strip_prefix(prefix).with_context(|| {
12178                            format!("line did not start with prefix {prefix:?}: {line:?}")
12179                        })
12180                    } else {
12181                        line_trimmed
12182                            .strip_prefix(&line_prefix.trim_start())
12183                            .with_context(|| {
12184                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12185                            })
12186                    }
12187                })
12188                .collect::<Result<Vec<_>, _>>()
12189                .log_err()
12190            else {
12191                continue;
12192            };
12193
12194            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12195                buffer
12196                    .language_settings_at(Point::new(start_row, 0), cx)
12197                    .preferred_line_length as usize
12198            });
12199
12200            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12201                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12202            } else {
12203                line_prefix.clone()
12204            };
12205
12206            let wrapped_text = {
12207                let mut wrapped_text = wrap_with_prefix(
12208                    line_prefix,
12209                    subsequent_lines_prefix,
12210                    lines_without_prefixes.join("\n"),
12211                    wrap_column,
12212                    tab_size,
12213                    options.preserve_existing_whitespace,
12214                );
12215
12216                if let Some((indent, delimiter)) = first_line_delimiter {
12217                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12218                }
12219                if let Some(last_line) = last_line_delimiter {
12220                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12221                }
12222
12223                wrapped_text
12224            };
12225
12226            // TODO: should always use char-based diff while still supporting cursor behavior that
12227            // matches vim.
12228            let mut diff_options = DiffOptions::default();
12229            if options.override_language_settings {
12230                diff_options.max_word_diff_len = 0;
12231                diff_options.max_word_diff_line_count = 0;
12232            } else {
12233                diff_options.max_word_diff_len = usize::MAX;
12234                diff_options.max_word_diff_line_count = usize::MAX;
12235            }
12236
12237            for (old_range, new_text) in
12238                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12239            {
12240                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12241                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12242                edits.push((edit_start..edit_end, new_text));
12243            }
12244
12245            rewrapped_row_ranges.push(start_row..=end_row);
12246        }
12247
12248        self.buffer
12249            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12250    }
12251
12252    pub fn cut_common(
12253        &mut self,
12254        cut_no_selection_line: bool,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) -> ClipboardItem {
12258        let mut text = String::new();
12259        let buffer = self.buffer.read(cx).snapshot(cx);
12260        let mut selections = self.selections.all::<Point>(cx);
12261        let mut clipboard_selections = Vec::with_capacity(selections.len());
12262        {
12263            let max_point = buffer.max_point();
12264            let mut is_first = true;
12265            for selection in &mut selections {
12266                let is_entire_line =
12267                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12268                if is_entire_line {
12269                    selection.start = Point::new(selection.start.row, 0);
12270                    if !selection.is_empty() && selection.end.column == 0 {
12271                        selection.end = cmp::min(max_point, selection.end);
12272                    } else {
12273                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12274                    }
12275                    selection.goal = SelectionGoal::None;
12276                }
12277                if is_first {
12278                    is_first = false;
12279                } else {
12280                    text += "\n";
12281                }
12282                let mut len = 0;
12283                for chunk in buffer.text_for_range(selection.start..selection.end) {
12284                    text.push_str(chunk);
12285                    len += chunk.len();
12286                }
12287                clipboard_selections.push(ClipboardSelection {
12288                    len,
12289                    is_entire_line,
12290                    first_line_indent: buffer
12291                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12292                        .len,
12293                });
12294            }
12295        }
12296
12297        self.transact(window, cx, |this, window, cx| {
12298            this.change_selections(Default::default(), window, cx, |s| {
12299                s.select(selections);
12300            });
12301            this.insert("", window, cx);
12302        });
12303        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12304    }
12305
12306    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12308        let item = self.cut_common(true, window, cx);
12309        cx.write_to_clipboard(item);
12310    }
12311
12312    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12314        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12315            s.move_with(|snapshot, sel| {
12316                if sel.is_empty() {
12317                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12318                }
12319                if sel.is_empty() {
12320                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12321                }
12322            });
12323        });
12324        let item = self.cut_common(true, window, cx);
12325        cx.set_global(KillRing(item))
12326    }
12327
12328    pub fn kill_ring_yank(
12329        &mut self,
12330        _: &KillRingYank,
12331        window: &mut Window,
12332        cx: &mut Context<Self>,
12333    ) {
12334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12335        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12336            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12337                (kill_ring.text().to_string(), kill_ring.metadata_json())
12338            } else {
12339                return;
12340            }
12341        } else {
12342            return;
12343        };
12344        self.do_paste(&text, metadata, false, window, cx);
12345    }
12346
12347    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12348        self.do_copy(true, cx);
12349    }
12350
12351    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12352        self.do_copy(false, cx);
12353    }
12354
12355    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12356        let selections = self.selections.all::<Point>(cx);
12357        let buffer = self.buffer.read(cx).read(cx);
12358        let mut text = String::new();
12359
12360        let mut clipboard_selections = Vec::with_capacity(selections.len());
12361        {
12362            let max_point = buffer.max_point();
12363            let mut is_first = true;
12364            for selection in &selections {
12365                let mut start = selection.start;
12366                let mut end = selection.end;
12367                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12368                if is_entire_line {
12369                    start = Point::new(start.row, 0);
12370                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12371                }
12372
12373                let mut trimmed_selections = Vec::new();
12374                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12375                    let row = MultiBufferRow(start.row);
12376                    let first_indent = buffer.indent_size_for_line(row);
12377                    if first_indent.len == 0 || start.column > first_indent.len {
12378                        trimmed_selections.push(start..end);
12379                    } else {
12380                        trimmed_selections.push(
12381                            Point::new(row.0, first_indent.len)
12382                                ..Point::new(row.0, buffer.line_len(row)),
12383                        );
12384                        for row in start.row + 1..=end.row {
12385                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12386                            if row == end.row {
12387                                line_len = end.column;
12388                            }
12389                            if line_len == 0 {
12390                                trimmed_selections
12391                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12392                                continue;
12393                            }
12394                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12395                            if row_indent_size.len >= first_indent.len {
12396                                trimmed_selections.push(
12397                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12398                                );
12399                            } else {
12400                                trimmed_selections.clear();
12401                                trimmed_selections.push(start..end);
12402                                break;
12403                            }
12404                        }
12405                    }
12406                } else {
12407                    trimmed_selections.push(start..end);
12408                }
12409
12410                for trimmed_range in trimmed_selections {
12411                    if is_first {
12412                        is_first = false;
12413                    } else {
12414                        text += "\n";
12415                    }
12416                    let mut len = 0;
12417                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12418                        text.push_str(chunk);
12419                        len += chunk.len();
12420                    }
12421                    clipboard_selections.push(ClipboardSelection {
12422                        len,
12423                        is_entire_line,
12424                        first_line_indent: buffer
12425                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12426                            .len,
12427                    });
12428                }
12429            }
12430        }
12431
12432        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12433            text,
12434            clipboard_selections,
12435        ));
12436    }
12437
12438    pub fn do_paste(
12439        &mut self,
12440        text: &String,
12441        clipboard_selections: Option<Vec<ClipboardSelection>>,
12442        handle_entire_lines: bool,
12443        window: &mut Window,
12444        cx: &mut Context<Self>,
12445    ) {
12446        if self.read_only(cx) {
12447            return;
12448        }
12449
12450        let clipboard_text = Cow::Borrowed(text);
12451
12452        self.transact(window, cx, |this, window, cx| {
12453            let had_active_edit_prediction = this.has_active_edit_prediction();
12454
12455            if let Some(mut clipboard_selections) = clipboard_selections {
12456                let old_selections = this.selections.all::<usize>(cx);
12457                let all_selections_were_entire_line =
12458                    clipboard_selections.iter().all(|s| s.is_entire_line);
12459                let first_selection_indent_column =
12460                    clipboard_selections.first().map(|s| s.first_line_indent);
12461                if clipboard_selections.len() != old_selections.len() {
12462                    clipboard_selections.drain(..);
12463                }
12464                let cursor_offset = this.selections.last::<usize>(cx).head();
12465                let mut auto_indent_on_paste = true;
12466
12467                this.buffer.update(cx, |buffer, cx| {
12468                    let snapshot = buffer.read(cx);
12469                    auto_indent_on_paste = snapshot
12470                        .language_settings_at(cursor_offset, cx)
12471                        .auto_indent_on_paste;
12472
12473                    let mut start_offset = 0;
12474                    let mut edits = Vec::new();
12475                    let mut original_indent_columns = Vec::new();
12476                    for (ix, selection) in old_selections.iter().enumerate() {
12477                        let to_insert;
12478                        let entire_line;
12479                        let original_indent_column;
12480                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12481                            let end_offset = start_offset + clipboard_selection.len;
12482                            to_insert = &clipboard_text[start_offset..end_offset];
12483                            entire_line = clipboard_selection.is_entire_line;
12484                            start_offset = end_offset + 1;
12485                            original_indent_column = Some(clipboard_selection.first_line_indent);
12486                        } else {
12487                            to_insert = clipboard_text.as_str();
12488                            entire_line = all_selections_were_entire_line;
12489                            original_indent_column = first_selection_indent_column
12490                        }
12491
12492                        // If the corresponding selection was empty when this slice of the
12493                        // clipboard text was written, then the entire line containing the
12494                        // selection was copied. If this selection is also currently empty,
12495                        // then paste the line before the current line of the buffer.
12496                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12497                            let column = selection.start.to_point(&snapshot).column as usize;
12498                            let line_start = selection.start - column;
12499                            line_start..line_start
12500                        } else {
12501                            selection.range()
12502                        };
12503
12504                        edits.push((range, to_insert));
12505                        original_indent_columns.push(original_indent_column);
12506                    }
12507                    drop(snapshot);
12508
12509                    buffer.edit(
12510                        edits,
12511                        if auto_indent_on_paste {
12512                            Some(AutoindentMode::Block {
12513                                original_indent_columns,
12514                            })
12515                        } else {
12516                            None
12517                        },
12518                        cx,
12519                    );
12520                });
12521
12522                let selections = this.selections.all::<usize>(cx);
12523                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12524            } else {
12525                this.insert(&clipboard_text, window, cx);
12526            }
12527
12528            let trigger_in_words =
12529                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12530
12531            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12532        });
12533    }
12534
12535    pub fn diff_clipboard_with_selection(
12536        &mut self,
12537        _: &DiffClipboardWithSelection,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        let selections = self.selections.all::<usize>(cx);
12542
12543        if selections.is_empty() {
12544            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12545            return;
12546        };
12547
12548        let clipboard_text = match cx.read_from_clipboard() {
12549            Some(item) => match item.entries().first() {
12550                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12551                _ => None,
12552            },
12553            None => None,
12554        };
12555
12556        let Some(clipboard_text) = clipboard_text else {
12557            log::warn!("Clipboard doesn't contain text.");
12558            return;
12559        };
12560
12561        window.dispatch_action(
12562            Box::new(DiffClipboardWithSelectionData {
12563                clipboard_text,
12564                editor: cx.entity(),
12565            }),
12566            cx,
12567        );
12568    }
12569
12570    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12571        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12572        if let Some(item) = cx.read_from_clipboard() {
12573            let entries = item.entries();
12574
12575            match entries.first() {
12576                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12577                // of all the pasted entries.
12578                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12579                    .do_paste(
12580                        clipboard_string.text(),
12581                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12582                        true,
12583                        window,
12584                        cx,
12585                    ),
12586                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12587            }
12588        }
12589    }
12590
12591    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12592        if self.read_only(cx) {
12593            return;
12594        }
12595
12596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12597
12598        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12599            if let Some((selections, _)) =
12600                self.selection_history.transaction(transaction_id).cloned()
12601            {
12602                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12603                    s.select_anchors(selections.to_vec());
12604                });
12605            } else {
12606                log::error!(
12607                    "No entry in selection_history found for undo. \
12608                     This may correspond to a bug where undo does not update the selection. \
12609                     If this is occurring, please add details to \
12610                     https://github.com/zed-industries/zed/issues/22692"
12611                );
12612            }
12613            self.request_autoscroll(Autoscroll::fit(), cx);
12614            self.unmark_text(window, cx);
12615            self.refresh_edit_prediction(true, false, window, cx);
12616            cx.emit(EditorEvent::Edited { transaction_id });
12617            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12618        }
12619    }
12620
12621    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12622        if self.read_only(cx) {
12623            return;
12624        }
12625
12626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12627
12628        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12629            if let Some((_, Some(selections))) =
12630                self.selection_history.transaction(transaction_id).cloned()
12631            {
12632                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12633                    s.select_anchors(selections.to_vec());
12634                });
12635            } else {
12636                log::error!(
12637                    "No entry in selection_history found for redo. \
12638                     This may correspond to a bug where undo does not update the selection. \
12639                     If this is occurring, please add details to \
12640                     https://github.com/zed-industries/zed/issues/22692"
12641                );
12642            }
12643            self.request_autoscroll(Autoscroll::fit(), cx);
12644            self.unmark_text(window, cx);
12645            self.refresh_edit_prediction(true, false, window, cx);
12646            cx.emit(EditorEvent::Edited { transaction_id });
12647        }
12648    }
12649
12650    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12651        self.buffer
12652            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12653    }
12654
12655    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12656        self.buffer
12657            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12658    }
12659
12660    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12662        self.change_selections(Default::default(), window, cx, |s| {
12663            s.move_with(|map, selection| {
12664                let cursor = if selection.is_empty() {
12665                    movement::left(map, selection.start)
12666                } else {
12667                    selection.start
12668                };
12669                selection.collapse_to(cursor, SelectionGoal::None);
12670            });
12671        })
12672    }
12673
12674    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12676        self.change_selections(Default::default(), window, cx, |s| {
12677            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12678        })
12679    }
12680
12681    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12683        self.change_selections(Default::default(), window, cx, |s| {
12684            s.move_with(|map, selection| {
12685                let cursor = if selection.is_empty() {
12686                    movement::right(map, selection.end)
12687                } else {
12688                    selection.end
12689                };
12690                selection.collapse_to(cursor, SelectionGoal::None)
12691            });
12692        })
12693    }
12694
12695    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12697        self.change_selections(Default::default(), window, cx, |s| {
12698            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12699        })
12700    }
12701
12702    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12703        if self.take_rename(true, window, cx).is_some() {
12704            return;
12705        }
12706
12707        if self.mode.is_single_line() {
12708            cx.propagate();
12709            return;
12710        }
12711
12712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12713
12714        let text_layout_details = &self.text_layout_details(window);
12715        let selection_count = self.selections.count();
12716        let first_selection = self.selections.first_anchor();
12717
12718        self.change_selections(Default::default(), window, cx, |s| {
12719            s.move_with(|map, selection| {
12720                if !selection.is_empty() {
12721                    selection.goal = SelectionGoal::None;
12722                }
12723                let (cursor, goal) = movement::up(
12724                    map,
12725                    selection.start,
12726                    selection.goal,
12727                    false,
12728                    text_layout_details,
12729                );
12730                selection.collapse_to(cursor, goal);
12731            });
12732        });
12733
12734        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12735        {
12736            cx.propagate();
12737        }
12738    }
12739
12740    pub fn move_up_by_lines(
12741        &mut self,
12742        action: &MoveUpByLines,
12743        window: &mut Window,
12744        cx: &mut Context<Self>,
12745    ) {
12746        if self.take_rename(true, window, cx).is_some() {
12747            return;
12748        }
12749
12750        if self.mode.is_single_line() {
12751            cx.propagate();
12752            return;
12753        }
12754
12755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12756
12757        let text_layout_details = &self.text_layout_details(window);
12758
12759        self.change_selections(Default::default(), window, cx, |s| {
12760            s.move_with(|map, selection| {
12761                if !selection.is_empty() {
12762                    selection.goal = SelectionGoal::None;
12763                }
12764                let (cursor, goal) = movement::up_by_rows(
12765                    map,
12766                    selection.start,
12767                    action.lines,
12768                    selection.goal,
12769                    false,
12770                    text_layout_details,
12771                );
12772                selection.collapse_to(cursor, goal);
12773            });
12774        })
12775    }
12776
12777    pub fn move_down_by_lines(
12778        &mut self,
12779        action: &MoveDownByLines,
12780        window: &mut Window,
12781        cx: &mut Context<Self>,
12782    ) {
12783        if self.take_rename(true, window, cx).is_some() {
12784            return;
12785        }
12786
12787        if self.mode.is_single_line() {
12788            cx.propagate();
12789            return;
12790        }
12791
12792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12793
12794        let text_layout_details = &self.text_layout_details(window);
12795
12796        self.change_selections(Default::default(), window, cx, |s| {
12797            s.move_with(|map, selection| {
12798                if !selection.is_empty() {
12799                    selection.goal = SelectionGoal::None;
12800                }
12801                let (cursor, goal) = movement::down_by_rows(
12802                    map,
12803                    selection.start,
12804                    action.lines,
12805                    selection.goal,
12806                    false,
12807                    text_layout_details,
12808                );
12809                selection.collapse_to(cursor, goal);
12810            });
12811        })
12812    }
12813
12814    pub fn select_down_by_lines(
12815        &mut self,
12816        action: &SelectDownByLines,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821        let text_layout_details = &self.text_layout_details(window);
12822        self.change_selections(Default::default(), window, cx, |s| {
12823            s.move_heads_with(|map, head, goal| {
12824                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12825            })
12826        })
12827    }
12828
12829    pub fn select_up_by_lines(
12830        &mut self,
12831        action: &SelectUpByLines,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) {
12835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12836        let text_layout_details = &self.text_layout_details(window);
12837        self.change_selections(Default::default(), window, cx, |s| {
12838            s.move_heads_with(|map, head, goal| {
12839                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12840            })
12841        })
12842    }
12843
12844    pub fn select_page_up(
12845        &mut self,
12846        _: &SelectPageUp,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        let Some(row_count) = self.visible_row_count() else {
12851            return;
12852        };
12853
12854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12855
12856        let text_layout_details = &self.text_layout_details(window);
12857
12858        self.change_selections(Default::default(), window, cx, |s| {
12859            s.move_heads_with(|map, head, goal| {
12860                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12861            })
12862        })
12863    }
12864
12865    pub fn move_page_up(
12866        &mut self,
12867        action: &MovePageUp,
12868        window: &mut Window,
12869        cx: &mut Context<Self>,
12870    ) {
12871        if self.take_rename(true, window, cx).is_some() {
12872            return;
12873        }
12874
12875        if self
12876            .context_menu
12877            .borrow_mut()
12878            .as_mut()
12879            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12880            .unwrap_or(false)
12881        {
12882            return;
12883        }
12884
12885        if matches!(self.mode, EditorMode::SingleLine) {
12886            cx.propagate();
12887            return;
12888        }
12889
12890        let Some(row_count) = self.visible_row_count() else {
12891            return;
12892        };
12893
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895
12896        let effects = if action.center_cursor {
12897            SelectionEffects::scroll(Autoscroll::center())
12898        } else {
12899            SelectionEffects::default()
12900        };
12901
12902        let text_layout_details = &self.text_layout_details(window);
12903
12904        self.change_selections(effects, window, cx, |s| {
12905            s.move_with(|map, selection| {
12906                if !selection.is_empty() {
12907                    selection.goal = SelectionGoal::None;
12908                }
12909                let (cursor, goal) = movement::up_by_rows(
12910                    map,
12911                    selection.end,
12912                    row_count,
12913                    selection.goal,
12914                    false,
12915                    text_layout_details,
12916                );
12917                selection.collapse_to(cursor, goal);
12918            });
12919        });
12920    }
12921
12922    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12923        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12924        let text_layout_details = &self.text_layout_details(window);
12925        self.change_selections(Default::default(), window, cx, |s| {
12926            s.move_heads_with(|map, head, goal| {
12927                movement::up(map, head, goal, false, text_layout_details)
12928            })
12929        })
12930    }
12931
12932    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12933        self.take_rename(true, window, cx);
12934
12935        if self.mode.is_single_line() {
12936            cx.propagate();
12937            return;
12938        }
12939
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12941
12942        let text_layout_details = &self.text_layout_details(window);
12943        let selection_count = self.selections.count();
12944        let first_selection = self.selections.first_anchor();
12945
12946        self.change_selections(Default::default(), window, cx, |s| {
12947            s.move_with(|map, selection| {
12948                if !selection.is_empty() {
12949                    selection.goal = SelectionGoal::None;
12950                }
12951                let (cursor, goal) = movement::down(
12952                    map,
12953                    selection.end,
12954                    selection.goal,
12955                    false,
12956                    text_layout_details,
12957                );
12958                selection.collapse_to(cursor, goal);
12959            });
12960        });
12961
12962        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12963        {
12964            cx.propagate();
12965        }
12966    }
12967
12968    pub fn select_page_down(
12969        &mut self,
12970        _: &SelectPageDown,
12971        window: &mut Window,
12972        cx: &mut Context<Self>,
12973    ) {
12974        let Some(row_count) = self.visible_row_count() else {
12975            return;
12976        };
12977
12978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12979
12980        let text_layout_details = &self.text_layout_details(window);
12981
12982        self.change_selections(Default::default(), window, cx, |s| {
12983            s.move_heads_with(|map, head, goal| {
12984                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12985            })
12986        })
12987    }
12988
12989    pub fn move_page_down(
12990        &mut self,
12991        action: &MovePageDown,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        if self.take_rename(true, window, cx).is_some() {
12996            return;
12997        }
12998
12999        if self
13000            .context_menu
13001            .borrow_mut()
13002            .as_mut()
13003            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13004            .unwrap_or(false)
13005        {
13006            return;
13007        }
13008
13009        if matches!(self.mode, EditorMode::SingleLine) {
13010            cx.propagate();
13011            return;
13012        }
13013
13014        let Some(row_count) = self.visible_row_count() else {
13015            return;
13016        };
13017
13018        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13019
13020        let effects = if action.center_cursor {
13021            SelectionEffects::scroll(Autoscroll::center())
13022        } else {
13023            SelectionEffects::default()
13024        };
13025
13026        let text_layout_details = &self.text_layout_details(window);
13027        self.change_selections(effects, window, cx, |s| {
13028            s.move_with(|map, selection| {
13029                if !selection.is_empty() {
13030                    selection.goal = SelectionGoal::None;
13031                }
13032                let (cursor, goal) = movement::down_by_rows(
13033                    map,
13034                    selection.end,
13035                    row_count,
13036                    selection.goal,
13037                    false,
13038                    text_layout_details,
13039                );
13040                selection.collapse_to(cursor, goal);
13041            });
13042        });
13043    }
13044
13045    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13046        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13047        let text_layout_details = &self.text_layout_details(window);
13048        self.change_selections(Default::default(), window, cx, |s| {
13049            s.move_heads_with(|map, head, goal| {
13050                movement::down(map, head, goal, false, text_layout_details)
13051            })
13052        });
13053    }
13054
13055    pub fn context_menu_first(
13056        &mut self,
13057        _: &ContextMenuFirst,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13062            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13063        }
13064    }
13065
13066    pub fn context_menu_prev(
13067        &mut self,
13068        _: &ContextMenuPrevious,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13073            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13074        }
13075    }
13076
13077    pub fn context_menu_next(
13078        &mut self,
13079        _: &ContextMenuNext,
13080        window: &mut Window,
13081        cx: &mut Context<Self>,
13082    ) {
13083        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13084            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13085        }
13086    }
13087
13088    pub fn context_menu_last(
13089        &mut self,
13090        _: &ContextMenuLast,
13091        window: &mut Window,
13092        cx: &mut Context<Self>,
13093    ) {
13094        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13095            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13096        }
13097    }
13098
13099    pub fn signature_help_prev(
13100        &mut self,
13101        _: &SignatureHelpPrevious,
13102        _: &mut Window,
13103        cx: &mut Context<Self>,
13104    ) {
13105        if let Some(popover) = self.signature_help_state.popover_mut() {
13106            if popover.current_signature == 0 {
13107                popover.current_signature = popover.signatures.len() - 1;
13108            } else {
13109                popover.current_signature -= 1;
13110            }
13111            cx.notify();
13112        }
13113    }
13114
13115    pub fn signature_help_next(
13116        &mut self,
13117        _: &SignatureHelpNext,
13118        _: &mut Window,
13119        cx: &mut Context<Self>,
13120    ) {
13121        if let Some(popover) = self.signature_help_state.popover_mut() {
13122            if popover.current_signature + 1 == popover.signatures.len() {
13123                popover.current_signature = 0;
13124            } else {
13125                popover.current_signature += 1;
13126            }
13127            cx.notify();
13128        }
13129    }
13130
13131    pub fn move_to_previous_word_start(
13132        &mut self,
13133        _: &MoveToPreviousWordStart,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13138        self.change_selections(Default::default(), window, cx, |s| {
13139            s.move_cursors_with(|map, head, _| {
13140                (
13141                    movement::previous_word_start(map, head),
13142                    SelectionGoal::None,
13143                )
13144            });
13145        })
13146    }
13147
13148    pub fn move_to_previous_subword_start(
13149        &mut self,
13150        _: &MoveToPreviousSubwordStart,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13155        self.change_selections(Default::default(), window, cx, |s| {
13156            s.move_cursors_with(|map, head, _| {
13157                (
13158                    movement::previous_subword_start(map, head),
13159                    SelectionGoal::None,
13160                )
13161            });
13162        })
13163    }
13164
13165    pub fn select_to_previous_word_start(
13166        &mut self,
13167        _: &SelectToPreviousWordStart,
13168        window: &mut Window,
13169        cx: &mut Context<Self>,
13170    ) {
13171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13172        self.change_selections(Default::default(), window, cx, |s| {
13173            s.move_heads_with(|map, head, _| {
13174                (
13175                    movement::previous_word_start(map, head),
13176                    SelectionGoal::None,
13177                )
13178            });
13179        })
13180    }
13181
13182    pub fn select_to_previous_subword_start(
13183        &mut self,
13184        _: &SelectToPreviousSubwordStart,
13185        window: &mut Window,
13186        cx: &mut Context<Self>,
13187    ) {
13188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13189        self.change_selections(Default::default(), window, cx, |s| {
13190            s.move_heads_with(|map, head, _| {
13191                (
13192                    movement::previous_subword_start(map, head),
13193                    SelectionGoal::None,
13194                )
13195            });
13196        })
13197    }
13198
13199    pub fn delete_to_previous_word_start(
13200        &mut self,
13201        action: &DeleteToPreviousWordStart,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13206        self.transact(window, cx, |this, window, cx| {
13207            this.select_autoclose_pair(window, cx);
13208            this.change_selections(Default::default(), window, cx, |s| {
13209                s.move_with(|map, selection| {
13210                    if selection.is_empty() {
13211                        let mut cursor = if action.ignore_newlines {
13212                            movement::previous_word_start(map, selection.head())
13213                        } else {
13214                            movement::previous_word_start_or_newline(map, selection.head())
13215                        };
13216                        cursor = movement::adjust_greedy_deletion(
13217                            map,
13218                            selection.head(),
13219                            cursor,
13220                            action.ignore_brackets,
13221                        );
13222                        selection.set_head(cursor, SelectionGoal::None);
13223                    }
13224                });
13225            });
13226            this.insert("", window, cx);
13227        });
13228    }
13229
13230    pub fn delete_to_previous_subword_start(
13231        &mut self,
13232        _: &DeleteToPreviousSubwordStart,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13237        self.transact(window, cx, |this, window, cx| {
13238            this.select_autoclose_pair(window, cx);
13239            this.change_selections(Default::default(), window, cx, |s| {
13240                s.move_with(|map, selection| {
13241                    if selection.is_empty() {
13242                        let mut cursor = movement::previous_subword_start(map, selection.head());
13243                        cursor =
13244                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13245                        selection.set_head(cursor, SelectionGoal::None);
13246                    }
13247                });
13248            });
13249            this.insert("", window, cx);
13250        });
13251    }
13252
13253    pub fn move_to_next_word_end(
13254        &mut self,
13255        _: &MoveToNextWordEnd,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260        self.change_selections(Default::default(), window, cx, |s| {
13261            s.move_cursors_with(|map, head, _| {
13262                (movement::next_word_end(map, head), SelectionGoal::None)
13263            });
13264        })
13265    }
13266
13267    pub fn move_to_next_subword_end(
13268        &mut self,
13269        _: &MoveToNextSubwordEnd,
13270        window: &mut Window,
13271        cx: &mut Context<Self>,
13272    ) {
13273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13274        self.change_selections(Default::default(), window, cx, |s| {
13275            s.move_cursors_with(|map, head, _| {
13276                (movement::next_subword_end(map, head), SelectionGoal::None)
13277            });
13278        })
13279    }
13280
13281    pub fn select_to_next_word_end(
13282        &mut self,
13283        _: &SelectToNextWordEnd,
13284        window: &mut Window,
13285        cx: &mut Context<Self>,
13286    ) {
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13288        self.change_selections(Default::default(), window, cx, |s| {
13289            s.move_heads_with(|map, head, _| {
13290                (movement::next_word_end(map, head), SelectionGoal::None)
13291            });
13292        })
13293    }
13294
13295    pub fn select_to_next_subword_end(
13296        &mut self,
13297        _: &SelectToNextSubwordEnd,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13302        self.change_selections(Default::default(), window, cx, |s| {
13303            s.move_heads_with(|map, head, _| {
13304                (movement::next_subword_end(map, head), SelectionGoal::None)
13305            });
13306        })
13307    }
13308
13309    pub fn delete_to_next_word_end(
13310        &mut self,
13311        action: &DeleteToNextWordEnd,
13312        window: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13316        self.transact(window, cx, |this, window, cx| {
13317            this.change_selections(Default::default(), window, cx, |s| {
13318                s.move_with(|map, selection| {
13319                    if selection.is_empty() {
13320                        let mut cursor = if action.ignore_newlines {
13321                            movement::next_word_end(map, selection.head())
13322                        } else {
13323                            movement::next_word_end_or_newline(map, selection.head())
13324                        };
13325                        cursor = movement::adjust_greedy_deletion(
13326                            map,
13327                            selection.head(),
13328                            cursor,
13329                            action.ignore_brackets,
13330                        );
13331                        selection.set_head(cursor, SelectionGoal::None);
13332                    }
13333                });
13334            });
13335            this.insert("", window, cx);
13336        });
13337    }
13338
13339    pub fn delete_to_next_subword_end(
13340        &mut self,
13341        _: &DeleteToNextSubwordEnd,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) {
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13346        self.transact(window, cx, |this, window, cx| {
13347            this.change_selections(Default::default(), window, cx, |s| {
13348                s.move_with(|map, selection| {
13349                    if selection.is_empty() {
13350                        let mut cursor = movement::next_subword_end(map, selection.head());
13351                        cursor =
13352                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13353                        selection.set_head(cursor, SelectionGoal::None);
13354                    }
13355                });
13356            });
13357            this.insert("", window, cx);
13358        });
13359    }
13360
13361    pub fn move_to_beginning_of_line(
13362        &mut self,
13363        action: &MoveToBeginningOfLine,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13368        self.change_selections(Default::default(), window, cx, |s| {
13369            s.move_cursors_with(|map, head, _| {
13370                (
13371                    movement::indented_line_beginning(
13372                        map,
13373                        head,
13374                        action.stop_at_soft_wraps,
13375                        action.stop_at_indent,
13376                    ),
13377                    SelectionGoal::None,
13378                )
13379            });
13380        })
13381    }
13382
13383    pub fn select_to_beginning_of_line(
13384        &mut self,
13385        action: &SelectToBeginningOfLine,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) {
13389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13390        self.change_selections(Default::default(), window, cx, |s| {
13391            s.move_heads_with(|map, head, _| {
13392                (
13393                    movement::indented_line_beginning(
13394                        map,
13395                        head,
13396                        action.stop_at_soft_wraps,
13397                        action.stop_at_indent,
13398                    ),
13399                    SelectionGoal::None,
13400                )
13401            });
13402        });
13403    }
13404
13405    pub fn delete_to_beginning_of_line(
13406        &mut self,
13407        action: &DeleteToBeginningOfLine,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) {
13411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13412        self.transact(window, cx, |this, window, cx| {
13413            this.change_selections(Default::default(), window, cx, |s| {
13414                s.move_with(|_, selection| {
13415                    selection.reversed = true;
13416                });
13417            });
13418
13419            this.select_to_beginning_of_line(
13420                &SelectToBeginningOfLine {
13421                    stop_at_soft_wraps: false,
13422                    stop_at_indent: action.stop_at_indent,
13423                },
13424                window,
13425                cx,
13426            );
13427            this.backspace(&Backspace, window, cx);
13428        });
13429    }
13430
13431    pub fn move_to_end_of_line(
13432        &mut self,
13433        action: &MoveToEndOfLine,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        self.change_selections(Default::default(), window, cx, |s| {
13439            s.move_cursors_with(|map, head, _| {
13440                (
13441                    movement::line_end(map, head, action.stop_at_soft_wraps),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_end_of_line(
13449        &mut self,
13450        action: &SelectToEndOfLine,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        self.change_selections(Default::default(), window, cx, |s| {
13456            s.move_heads_with(|map, head, _| {
13457                (
13458                    movement::line_end(map, head, action.stop_at_soft_wraps),
13459                    SelectionGoal::None,
13460                )
13461            });
13462        })
13463    }
13464
13465    pub fn delete_to_end_of_line(
13466        &mut self,
13467        _: &DeleteToEndOfLine,
13468        window: &mut Window,
13469        cx: &mut Context<Self>,
13470    ) {
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13472        self.transact(window, cx, |this, window, cx| {
13473            this.select_to_end_of_line(
13474                &SelectToEndOfLine {
13475                    stop_at_soft_wraps: false,
13476                },
13477                window,
13478                cx,
13479            );
13480            this.delete(&Delete, window, cx);
13481        });
13482    }
13483
13484    pub fn cut_to_end_of_line(
13485        &mut self,
13486        action: &CutToEndOfLine,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13491        self.transact(window, cx, |this, window, cx| {
13492            this.select_to_end_of_line(
13493                &SelectToEndOfLine {
13494                    stop_at_soft_wraps: false,
13495                },
13496                window,
13497                cx,
13498            );
13499            if !action.stop_at_newlines {
13500                this.change_selections(Default::default(), window, cx, |s| {
13501                    s.move_with(|_, sel| {
13502                        if sel.is_empty() {
13503                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13504                        }
13505                    });
13506                });
13507            }
13508            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13509            let item = this.cut_common(false, window, cx);
13510            cx.write_to_clipboard(item);
13511        });
13512    }
13513
13514    pub fn move_to_start_of_paragraph(
13515        &mut self,
13516        _: &MoveToStartOfParagraph,
13517        window: &mut Window,
13518        cx: &mut Context<Self>,
13519    ) {
13520        if matches!(self.mode, EditorMode::SingleLine) {
13521            cx.propagate();
13522            return;
13523        }
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        self.change_selections(Default::default(), window, cx, |s| {
13526            s.move_with(|map, selection| {
13527                selection.collapse_to(
13528                    movement::start_of_paragraph(map, selection.head(), 1),
13529                    SelectionGoal::None,
13530                )
13531            });
13532        })
13533    }
13534
13535    pub fn move_to_end_of_paragraph(
13536        &mut self,
13537        _: &MoveToEndOfParagraph,
13538        window: &mut Window,
13539        cx: &mut Context<Self>,
13540    ) {
13541        if matches!(self.mode, EditorMode::SingleLine) {
13542            cx.propagate();
13543            return;
13544        }
13545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13546        self.change_selections(Default::default(), window, cx, |s| {
13547            s.move_with(|map, selection| {
13548                selection.collapse_to(
13549                    movement::end_of_paragraph(map, selection.head(), 1),
13550                    SelectionGoal::None,
13551                )
13552            });
13553        })
13554    }
13555
13556    pub fn select_to_start_of_paragraph(
13557        &mut self,
13558        _: &SelectToStartOfParagraph,
13559        window: &mut Window,
13560        cx: &mut Context<Self>,
13561    ) {
13562        if matches!(self.mode, EditorMode::SingleLine) {
13563            cx.propagate();
13564            return;
13565        }
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13567        self.change_selections(Default::default(), window, cx, |s| {
13568            s.move_heads_with(|map, head, _| {
13569                (
13570                    movement::start_of_paragraph(map, head, 1),
13571                    SelectionGoal::None,
13572                )
13573            });
13574        })
13575    }
13576
13577    pub fn select_to_end_of_paragraph(
13578        &mut self,
13579        _: &SelectToEndOfParagraph,
13580        window: &mut Window,
13581        cx: &mut Context<Self>,
13582    ) {
13583        if matches!(self.mode, EditorMode::SingleLine) {
13584            cx.propagate();
13585            return;
13586        }
13587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13588        self.change_selections(Default::default(), window, cx, |s| {
13589            s.move_heads_with(|map, head, _| {
13590                (
13591                    movement::end_of_paragraph(map, head, 1),
13592                    SelectionGoal::None,
13593                )
13594            });
13595        })
13596    }
13597
13598    pub fn move_to_start_of_excerpt(
13599        &mut self,
13600        _: &MoveToStartOfExcerpt,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        if matches!(self.mode, EditorMode::SingleLine) {
13605            cx.propagate();
13606            return;
13607        }
13608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13609        self.change_selections(Default::default(), window, cx, |s| {
13610            s.move_with(|map, selection| {
13611                selection.collapse_to(
13612                    movement::start_of_excerpt(
13613                        map,
13614                        selection.head(),
13615                        workspace::searchable::Direction::Prev,
13616                    ),
13617                    SelectionGoal::None,
13618                )
13619            });
13620        })
13621    }
13622
13623    pub fn move_to_start_of_next_excerpt(
13624        &mut self,
13625        _: &MoveToStartOfNextExcerpt,
13626        window: &mut Window,
13627        cx: &mut Context<Self>,
13628    ) {
13629        if matches!(self.mode, EditorMode::SingleLine) {
13630            cx.propagate();
13631            return;
13632        }
13633
13634        self.change_selections(Default::default(), window, cx, |s| {
13635            s.move_with(|map, selection| {
13636                selection.collapse_to(
13637                    movement::start_of_excerpt(
13638                        map,
13639                        selection.head(),
13640                        workspace::searchable::Direction::Next,
13641                    ),
13642                    SelectionGoal::None,
13643                )
13644            });
13645        })
13646    }
13647
13648    pub fn move_to_end_of_excerpt(
13649        &mut self,
13650        _: &MoveToEndOfExcerpt,
13651        window: &mut Window,
13652        cx: &mut Context<Self>,
13653    ) {
13654        if matches!(self.mode, EditorMode::SingleLine) {
13655            cx.propagate();
13656            return;
13657        }
13658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13659        self.change_selections(Default::default(), window, cx, |s| {
13660            s.move_with(|map, selection| {
13661                selection.collapse_to(
13662                    movement::end_of_excerpt(
13663                        map,
13664                        selection.head(),
13665                        workspace::searchable::Direction::Next,
13666                    ),
13667                    SelectionGoal::None,
13668                )
13669            });
13670        })
13671    }
13672
13673    pub fn move_to_end_of_previous_excerpt(
13674        &mut self,
13675        _: &MoveToEndOfPreviousExcerpt,
13676        window: &mut Window,
13677        cx: &mut Context<Self>,
13678    ) {
13679        if matches!(self.mode, EditorMode::SingleLine) {
13680            cx.propagate();
13681            return;
13682        }
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13684        self.change_selections(Default::default(), window, cx, |s| {
13685            s.move_with(|map, selection| {
13686                selection.collapse_to(
13687                    movement::end_of_excerpt(
13688                        map,
13689                        selection.head(),
13690                        workspace::searchable::Direction::Prev,
13691                    ),
13692                    SelectionGoal::None,
13693                )
13694            });
13695        })
13696    }
13697
13698    pub fn select_to_start_of_excerpt(
13699        &mut self,
13700        _: &SelectToStartOfExcerpt,
13701        window: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        if matches!(self.mode, EditorMode::SingleLine) {
13705            cx.propagate();
13706            return;
13707        }
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13709        self.change_selections(Default::default(), window, cx, |s| {
13710            s.move_heads_with(|map, head, _| {
13711                (
13712                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13713                    SelectionGoal::None,
13714                )
13715            });
13716        })
13717    }
13718
13719    pub fn select_to_start_of_next_excerpt(
13720        &mut self,
13721        _: &SelectToStartOfNextExcerpt,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        if matches!(self.mode, EditorMode::SingleLine) {
13726            cx.propagate();
13727            return;
13728        }
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13730        self.change_selections(Default::default(), window, cx, |s| {
13731            s.move_heads_with(|map, head, _| {
13732                (
13733                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13734                    SelectionGoal::None,
13735                )
13736            });
13737        })
13738    }
13739
13740    pub fn select_to_end_of_excerpt(
13741        &mut self,
13742        _: &SelectToEndOfExcerpt,
13743        window: &mut Window,
13744        cx: &mut Context<Self>,
13745    ) {
13746        if matches!(self.mode, EditorMode::SingleLine) {
13747            cx.propagate();
13748            return;
13749        }
13750        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13751        self.change_selections(Default::default(), window, cx, |s| {
13752            s.move_heads_with(|map, head, _| {
13753                (
13754                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13755                    SelectionGoal::None,
13756                )
13757            });
13758        })
13759    }
13760
13761    pub fn select_to_end_of_previous_excerpt(
13762        &mut self,
13763        _: &SelectToEndOfPreviousExcerpt,
13764        window: &mut Window,
13765        cx: &mut Context<Self>,
13766    ) {
13767        if matches!(self.mode, EditorMode::SingleLine) {
13768            cx.propagate();
13769            return;
13770        }
13771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13772        self.change_selections(Default::default(), window, cx, |s| {
13773            s.move_heads_with(|map, head, _| {
13774                (
13775                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13776                    SelectionGoal::None,
13777                )
13778            });
13779        })
13780    }
13781
13782    pub fn move_to_beginning(
13783        &mut self,
13784        _: &MoveToBeginning,
13785        window: &mut Window,
13786        cx: &mut Context<Self>,
13787    ) {
13788        if matches!(self.mode, EditorMode::SingleLine) {
13789            cx.propagate();
13790            return;
13791        }
13792        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13793        self.change_selections(Default::default(), window, cx, |s| {
13794            s.select_ranges(vec![0..0]);
13795        });
13796    }
13797
13798    pub fn select_to_beginning(
13799        &mut self,
13800        _: &SelectToBeginning,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        let mut selection = self.selections.last::<Point>(cx);
13805        selection.set_head(Point::zero(), SelectionGoal::None);
13806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13807        self.change_selections(Default::default(), window, cx, |s| {
13808            s.select(vec![selection]);
13809        });
13810    }
13811
13812    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13813        if matches!(self.mode, EditorMode::SingleLine) {
13814            cx.propagate();
13815            return;
13816        }
13817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13818        let cursor = self.buffer.read(cx).read(cx).len();
13819        self.change_selections(Default::default(), window, cx, |s| {
13820            s.select_ranges(vec![cursor..cursor])
13821        });
13822    }
13823
13824    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13825        self.nav_history = nav_history;
13826    }
13827
13828    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13829        self.nav_history.as_ref()
13830    }
13831
13832    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13833        self.push_to_nav_history(
13834            self.selections.newest_anchor().head(),
13835            None,
13836            false,
13837            true,
13838            cx,
13839        );
13840    }
13841
13842    fn push_to_nav_history(
13843        &mut self,
13844        cursor_anchor: Anchor,
13845        new_position: Option<Point>,
13846        is_deactivate: bool,
13847        always: bool,
13848        cx: &mut Context<Self>,
13849    ) {
13850        if let Some(nav_history) = self.nav_history.as_mut() {
13851            let buffer = self.buffer.read(cx).read(cx);
13852            let cursor_position = cursor_anchor.to_point(&buffer);
13853            let scroll_state = self.scroll_manager.anchor();
13854            let scroll_top_row = scroll_state.top_row(&buffer);
13855            drop(buffer);
13856
13857            if let Some(new_position) = new_position {
13858                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13859                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13860                    return;
13861                }
13862            }
13863
13864            nav_history.push(
13865                Some(NavigationData {
13866                    cursor_anchor,
13867                    cursor_position,
13868                    scroll_anchor: scroll_state,
13869                    scroll_top_row,
13870                }),
13871                cx,
13872            );
13873            cx.emit(EditorEvent::PushedToNavHistory {
13874                anchor: cursor_anchor,
13875                is_deactivate,
13876            })
13877        }
13878    }
13879
13880    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13882        let buffer = self.buffer.read(cx).snapshot(cx);
13883        let mut selection = self.selections.first::<usize>(cx);
13884        selection.set_head(buffer.len(), SelectionGoal::None);
13885        self.change_selections(Default::default(), window, cx, |s| {
13886            s.select(vec![selection]);
13887        });
13888    }
13889
13890    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13892        let end = self.buffer.read(cx).read(cx).len();
13893        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13894            s.select_ranges(vec![0..end]);
13895        });
13896    }
13897
13898    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13900        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13901        let mut selections = self.selections.all::<Point>(cx);
13902        let max_point = display_map.buffer_snapshot.max_point();
13903        for selection in &mut selections {
13904            let rows = selection.spanned_rows(true, &display_map);
13905            selection.start = Point::new(rows.start.0, 0);
13906            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13907            selection.reversed = false;
13908        }
13909        self.change_selections(Default::default(), window, cx, |s| {
13910            s.select(selections);
13911        });
13912    }
13913
13914    pub fn split_selection_into_lines(
13915        &mut self,
13916        action: &SplitSelectionIntoLines,
13917        window: &mut Window,
13918        cx: &mut Context<Self>,
13919    ) {
13920        let selections = self
13921            .selections
13922            .all::<Point>(cx)
13923            .into_iter()
13924            .map(|selection| selection.start..selection.end)
13925            .collect::<Vec<_>>();
13926        self.unfold_ranges(&selections, true, true, cx);
13927
13928        let mut new_selection_ranges = Vec::new();
13929        {
13930            let buffer = self.buffer.read(cx).read(cx);
13931            for selection in selections {
13932                for row in selection.start.row..selection.end.row {
13933                    let line_start = Point::new(row, 0);
13934                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13935
13936                    if action.keep_selections {
13937                        // Keep the selection range for each line
13938                        let selection_start = if row == selection.start.row {
13939                            selection.start
13940                        } else {
13941                            line_start
13942                        };
13943                        new_selection_ranges.push(selection_start..line_end);
13944                    } else {
13945                        // Collapse to cursor at end of line
13946                        new_selection_ranges.push(line_end..line_end);
13947                    }
13948                }
13949
13950                let is_multiline_selection = selection.start.row != selection.end.row;
13951                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13952                // so this action feels more ergonomic when paired with other selection operations
13953                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13954                if !should_skip_last {
13955                    if action.keep_selections {
13956                        if is_multiline_selection {
13957                            let line_start = Point::new(selection.end.row, 0);
13958                            new_selection_ranges.push(line_start..selection.end);
13959                        } else {
13960                            new_selection_ranges.push(selection.start..selection.end);
13961                        }
13962                    } else {
13963                        new_selection_ranges.push(selection.end..selection.end);
13964                    }
13965                }
13966            }
13967        }
13968        self.change_selections(Default::default(), window, cx, |s| {
13969            s.select_ranges(new_selection_ranges);
13970        });
13971    }
13972
13973    pub fn add_selection_above(
13974        &mut self,
13975        _: &AddSelectionAbove,
13976        window: &mut Window,
13977        cx: &mut Context<Self>,
13978    ) {
13979        self.add_selection(true, window, cx);
13980    }
13981
13982    pub fn add_selection_below(
13983        &mut self,
13984        _: &AddSelectionBelow,
13985        window: &mut Window,
13986        cx: &mut Context<Self>,
13987    ) {
13988        self.add_selection(false, window, cx);
13989    }
13990
13991    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13993
13994        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13995        let all_selections = self.selections.all::<Point>(cx);
13996        let text_layout_details = self.text_layout_details(window);
13997
13998        let (mut columnar_selections, new_selections_to_columnarize) = {
13999            if let Some(state) = self.add_selections_state.as_ref() {
14000                let columnar_selection_ids: HashSet<_> = state
14001                    .groups
14002                    .iter()
14003                    .flat_map(|group| group.stack.iter())
14004                    .copied()
14005                    .collect();
14006
14007                all_selections
14008                    .into_iter()
14009                    .partition(|s| columnar_selection_ids.contains(&s.id))
14010            } else {
14011                (Vec::new(), all_selections)
14012            }
14013        };
14014
14015        let mut state = self
14016            .add_selections_state
14017            .take()
14018            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14019
14020        for selection in new_selections_to_columnarize {
14021            let range = selection.display_range(&display_map).sorted();
14022            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14023            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14024            let positions = start_x.min(end_x)..start_x.max(end_x);
14025            let mut stack = Vec::new();
14026            for row in range.start.row().0..=range.end.row().0 {
14027                if let Some(selection) = self.selections.build_columnar_selection(
14028                    &display_map,
14029                    DisplayRow(row),
14030                    &positions,
14031                    selection.reversed,
14032                    &text_layout_details,
14033                ) {
14034                    stack.push(selection.id);
14035                    columnar_selections.push(selection);
14036                }
14037            }
14038            if !stack.is_empty() {
14039                if above {
14040                    stack.reverse();
14041                }
14042                state.groups.push(AddSelectionsGroup { above, stack });
14043            }
14044        }
14045
14046        let mut final_selections = Vec::new();
14047        let end_row = if above {
14048            DisplayRow(0)
14049        } else {
14050            display_map.max_point().row()
14051        };
14052
14053        let mut last_added_item_per_group = HashMap::default();
14054        for group in state.groups.iter_mut() {
14055            if let Some(last_id) = group.stack.last() {
14056                last_added_item_per_group.insert(*last_id, group);
14057            }
14058        }
14059
14060        for selection in columnar_selections {
14061            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14062                if above == group.above {
14063                    let range = selection.display_range(&display_map).sorted();
14064                    debug_assert_eq!(range.start.row(), range.end.row());
14065                    let mut row = range.start.row();
14066                    let positions =
14067                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14068                            px(start)..px(end)
14069                        } else {
14070                            let start_x =
14071                                display_map.x_for_display_point(range.start, &text_layout_details);
14072                            let end_x =
14073                                display_map.x_for_display_point(range.end, &text_layout_details);
14074                            start_x.min(end_x)..start_x.max(end_x)
14075                        };
14076
14077                    let mut maybe_new_selection = None;
14078                    while row != end_row {
14079                        if above {
14080                            row.0 -= 1;
14081                        } else {
14082                            row.0 += 1;
14083                        }
14084                        if let Some(new_selection) = self.selections.build_columnar_selection(
14085                            &display_map,
14086                            row,
14087                            &positions,
14088                            selection.reversed,
14089                            &text_layout_details,
14090                        ) {
14091                            maybe_new_selection = Some(new_selection);
14092                            break;
14093                        }
14094                    }
14095
14096                    if let Some(new_selection) = maybe_new_selection {
14097                        group.stack.push(new_selection.id);
14098                        if above {
14099                            final_selections.push(new_selection);
14100                            final_selections.push(selection);
14101                        } else {
14102                            final_selections.push(selection);
14103                            final_selections.push(new_selection);
14104                        }
14105                    } else {
14106                        final_selections.push(selection);
14107                    }
14108                } else {
14109                    group.stack.pop();
14110                }
14111            } else {
14112                final_selections.push(selection);
14113            }
14114        }
14115
14116        self.change_selections(Default::default(), window, cx, |s| {
14117            s.select(final_selections);
14118        });
14119
14120        let final_selection_ids: HashSet<_> = self
14121            .selections
14122            .all::<Point>(cx)
14123            .iter()
14124            .map(|s| s.id)
14125            .collect();
14126        state.groups.retain_mut(|group| {
14127            // selections might get merged above so we remove invalid items from stacks
14128            group.stack.retain(|id| final_selection_ids.contains(id));
14129
14130            // single selection in stack can be treated as initial state
14131            group.stack.len() > 1
14132        });
14133
14134        if !state.groups.is_empty() {
14135            self.add_selections_state = Some(state);
14136        }
14137    }
14138
14139    fn select_match_ranges(
14140        &mut self,
14141        range: Range<usize>,
14142        reversed: bool,
14143        replace_newest: bool,
14144        auto_scroll: Option<Autoscroll>,
14145        window: &mut Window,
14146        cx: &mut Context<Editor>,
14147    ) {
14148        self.unfold_ranges(
14149            std::slice::from_ref(&range),
14150            false,
14151            auto_scroll.is_some(),
14152            cx,
14153        );
14154        let effects = if let Some(scroll) = auto_scroll {
14155            SelectionEffects::scroll(scroll)
14156        } else {
14157            SelectionEffects::no_scroll()
14158        };
14159        self.change_selections(effects, window, cx, |s| {
14160            if replace_newest {
14161                s.delete(s.newest_anchor().id);
14162            }
14163            if reversed {
14164                s.insert_range(range.end..range.start);
14165            } else {
14166                s.insert_range(range);
14167            }
14168        });
14169    }
14170
14171    pub fn select_next_match_internal(
14172        &mut self,
14173        display_map: &DisplaySnapshot,
14174        replace_newest: bool,
14175        autoscroll: Option<Autoscroll>,
14176        window: &mut Window,
14177        cx: &mut Context<Self>,
14178    ) -> Result<()> {
14179        let buffer = &display_map.buffer_snapshot;
14180        let mut selections = self.selections.all::<usize>(cx);
14181        if let Some(mut select_next_state) = self.select_next_state.take() {
14182            let query = &select_next_state.query;
14183            if !select_next_state.done {
14184                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14185                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14186                let mut next_selected_range = None;
14187
14188                let bytes_after_last_selection =
14189                    buffer.bytes_in_range(last_selection.end..buffer.len());
14190                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14191                let query_matches = query
14192                    .stream_find_iter(bytes_after_last_selection)
14193                    .map(|result| (last_selection.end, result))
14194                    .chain(
14195                        query
14196                            .stream_find_iter(bytes_before_first_selection)
14197                            .map(|result| (0, result)),
14198                    );
14199
14200                for (start_offset, query_match) in query_matches {
14201                    let query_match = query_match.unwrap(); // can only fail due to I/O
14202                    let offset_range =
14203                        start_offset + query_match.start()..start_offset + query_match.end();
14204
14205                    if !select_next_state.wordwise
14206                        || (!buffer.is_inside_word(offset_range.start, false)
14207                            && !buffer.is_inside_word(offset_range.end, false))
14208                    {
14209                        // TODO: This is n^2, because we might check all the selections
14210                        if !selections
14211                            .iter()
14212                            .any(|selection| selection.range().overlaps(&offset_range))
14213                        {
14214                            next_selected_range = Some(offset_range);
14215                            break;
14216                        }
14217                    }
14218                }
14219
14220                if let Some(next_selected_range) = next_selected_range {
14221                    self.select_match_ranges(
14222                        next_selected_range,
14223                        last_selection.reversed,
14224                        replace_newest,
14225                        autoscroll,
14226                        window,
14227                        cx,
14228                    );
14229                } else {
14230                    select_next_state.done = true;
14231                }
14232            }
14233
14234            self.select_next_state = Some(select_next_state);
14235        } else {
14236            let mut only_carets = true;
14237            let mut same_text_selected = true;
14238            let mut selected_text = None;
14239
14240            let mut selections_iter = selections.iter().peekable();
14241            while let Some(selection) = selections_iter.next() {
14242                if selection.start != selection.end {
14243                    only_carets = false;
14244                }
14245
14246                if same_text_selected {
14247                    if selected_text.is_none() {
14248                        selected_text =
14249                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14250                    }
14251
14252                    if let Some(next_selection) = selections_iter.peek() {
14253                        if next_selection.range().len() == selection.range().len() {
14254                            let next_selected_text = buffer
14255                                .text_for_range(next_selection.range())
14256                                .collect::<String>();
14257                            if Some(next_selected_text) != selected_text {
14258                                same_text_selected = false;
14259                                selected_text = None;
14260                            }
14261                        } else {
14262                            same_text_selected = false;
14263                            selected_text = None;
14264                        }
14265                    }
14266                }
14267            }
14268
14269            if only_carets {
14270                for selection in &mut selections {
14271                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14272                    selection.start = word_range.start;
14273                    selection.end = word_range.end;
14274                    selection.goal = SelectionGoal::None;
14275                    selection.reversed = false;
14276                    self.select_match_ranges(
14277                        selection.start..selection.end,
14278                        selection.reversed,
14279                        replace_newest,
14280                        autoscroll,
14281                        window,
14282                        cx,
14283                    );
14284                }
14285
14286                if selections.len() == 1 {
14287                    let selection = selections
14288                        .last()
14289                        .expect("ensured that there's only one selection");
14290                    let query = buffer
14291                        .text_for_range(selection.start..selection.end)
14292                        .collect::<String>();
14293                    let is_empty = query.is_empty();
14294                    let select_state = SelectNextState {
14295                        query: AhoCorasick::new(&[query])?,
14296                        wordwise: true,
14297                        done: is_empty,
14298                    };
14299                    self.select_next_state = Some(select_state);
14300                } else {
14301                    self.select_next_state = None;
14302                }
14303            } else if let Some(selected_text) = selected_text {
14304                self.select_next_state = Some(SelectNextState {
14305                    query: AhoCorasick::new(&[selected_text])?,
14306                    wordwise: false,
14307                    done: false,
14308                });
14309                self.select_next_match_internal(
14310                    display_map,
14311                    replace_newest,
14312                    autoscroll,
14313                    window,
14314                    cx,
14315                )?;
14316            }
14317        }
14318        Ok(())
14319    }
14320
14321    pub fn select_all_matches(
14322        &mut self,
14323        _action: &SelectAllMatches,
14324        window: &mut Window,
14325        cx: &mut Context<Self>,
14326    ) -> Result<()> {
14327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14328
14329        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14330
14331        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14332        let Some(select_next_state) = self.select_next_state.as_mut() else {
14333            return Ok(());
14334        };
14335        if select_next_state.done {
14336            return Ok(());
14337        }
14338
14339        let mut new_selections = Vec::new();
14340
14341        let reversed = self.selections.oldest::<usize>(cx).reversed;
14342        let buffer = &display_map.buffer_snapshot;
14343        let query_matches = select_next_state
14344            .query
14345            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14346
14347        for query_match in query_matches.into_iter() {
14348            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14349            let offset_range = if reversed {
14350                query_match.end()..query_match.start()
14351            } else {
14352                query_match.start()..query_match.end()
14353            };
14354
14355            if !select_next_state.wordwise
14356                || (!buffer.is_inside_word(offset_range.start, false)
14357                    && !buffer.is_inside_word(offset_range.end, false))
14358            {
14359                new_selections.push(offset_range.start..offset_range.end);
14360            }
14361        }
14362
14363        select_next_state.done = true;
14364
14365        if new_selections.is_empty() {
14366            log::error!("bug: new_selections is empty in select_all_matches");
14367            return Ok(());
14368        }
14369
14370        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14371        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14372            selections.select_ranges(new_selections)
14373        });
14374
14375        Ok(())
14376    }
14377
14378    pub fn select_next(
14379        &mut self,
14380        action: &SelectNext,
14381        window: &mut Window,
14382        cx: &mut Context<Self>,
14383    ) -> Result<()> {
14384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14386        self.select_next_match_internal(
14387            &display_map,
14388            action.replace_newest,
14389            Some(Autoscroll::newest()),
14390            window,
14391            cx,
14392        )?;
14393        Ok(())
14394    }
14395
14396    pub fn select_previous(
14397        &mut self,
14398        action: &SelectPrevious,
14399        window: &mut Window,
14400        cx: &mut Context<Self>,
14401    ) -> Result<()> {
14402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14403        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14404        let buffer = &display_map.buffer_snapshot;
14405        let mut selections = self.selections.all::<usize>(cx);
14406        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14407            let query = &select_prev_state.query;
14408            if !select_prev_state.done {
14409                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14410                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14411                let mut next_selected_range = None;
14412                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14413                let bytes_before_last_selection =
14414                    buffer.reversed_bytes_in_range(0..last_selection.start);
14415                let bytes_after_first_selection =
14416                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14417                let query_matches = query
14418                    .stream_find_iter(bytes_before_last_selection)
14419                    .map(|result| (last_selection.start, result))
14420                    .chain(
14421                        query
14422                            .stream_find_iter(bytes_after_first_selection)
14423                            .map(|result| (buffer.len(), result)),
14424                    );
14425                for (end_offset, query_match) in query_matches {
14426                    let query_match = query_match.unwrap(); // can only fail due to I/O
14427                    let offset_range =
14428                        end_offset - query_match.end()..end_offset - query_match.start();
14429
14430                    if !select_prev_state.wordwise
14431                        || (!buffer.is_inside_word(offset_range.start, false)
14432                            && !buffer.is_inside_word(offset_range.end, false))
14433                    {
14434                        next_selected_range = Some(offset_range);
14435                        break;
14436                    }
14437                }
14438
14439                if let Some(next_selected_range) = next_selected_range {
14440                    self.select_match_ranges(
14441                        next_selected_range,
14442                        last_selection.reversed,
14443                        action.replace_newest,
14444                        Some(Autoscroll::newest()),
14445                        window,
14446                        cx,
14447                    );
14448                } else {
14449                    select_prev_state.done = true;
14450                }
14451            }
14452
14453            self.select_prev_state = Some(select_prev_state);
14454        } else {
14455            let mut only_carets = true;
14456            let mut same_text_selected = true;
14457            let mut selected_text = None;
14458
14459            let mut selections_iter = selections.iter().peekable();
14460            while let Some(selection) = selections_iter.next() {
14461                if selection.start != selection.end {
14462                    only_carets = false;
14463                }
14464
14465                if same_text_selected {
14466                    if selected_text.is_none() {
14467                        selected_text =
14468                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14469                    }
14470
14471                    if let Some(next_selection) = selections_iter.peek() {
14472                        if next_selection.range().len() == selection.range().len() {
14473                            let next_selected_text = buffer
14474                                .text_for_range(next_selection.range())
14475                                .collect::<String>();
14476                            if Some(next_selected_text) != selected_text {
14477                                same_text_selected = false;
14478                                selected_text = None;
14479                            }
14480                        } else {
14481                            same_text_selected = false;
14482                            selected_text = None;
14483                        }
14484                    }
14485                }
14486            }
14487
14488            if only_carets {
14489                for selection in &mut selections {
14490                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14491                    selection.start = word_range.start;
14492                    selection.end = word_range.end;
14493                    selection.goal = SelectionGoal::None;
14494                    selection.reversed = false;
14495                    self.select_match_ranges(
14496                        selection.start..selection.end,
14497                        selection.reversed,
14498                        action.replace_newest,
14499                        Some(Autoscroll::newest()),
14500                        window,
14501                        cx,
14502                    );
14503                }
14504                if selections.len() == 1 {
14505                    let selection = selections
14506                        .last()
14507                        .expect("ensured that there's only one selection");
14508                    let query = buffer
14509                        .text_for_range(selection.start..selection.end)
14510                        .collect::<String>();
14511                    let is_empty = query.is_empty();
14512                    let select_state = SelectNextState {
14513                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14514                        wordwise: true,
14515                        done: is_empty,
14516                    };
14517                    self.select_prev_state = Some(select_state);
14518                } else {
14519                    self.select_prev_state = None;
14520                }
14521            } else if let Some(selected_text) = selected_text {
14522                self.select_prev_state = Some(SelectNextState {
14523                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14524                    wordwise: false,
14525                    done: false,
14526                });
14527                self.select_previous(action, window, cx)?;
14528            }
14529        }
14530        Ok(())
14531    }
14532
14533    pub fn find_next_match(
14534        &mut self,
14535        _: &FindNextMatch,
14536        window: &mut Window,
14537        cx: &mut Context<Self>,
14538    ) -> Result<()> {
14539        let selections = self.selections.disjoint_anchors();
14540        match selections.first() {
14541            Some(first) if selections.len() >= 2 => {
14542                self.change_selections(Default::default(), window, cx, |s| {
14543                    s.select_ranges([first.range()]);
14544                });
14545            }
14546            _ => self.select_next(
14547                &SelectNext {
14548                    replace_newest: true,
14549                },
14550                window,
14551                cx,
14552            )?,
14553        }
14554        Ok(())
14555    }
14556
14557    pub fn find_previous_match(
14558        &mut self,
14559        _: &FindPreviousMatch,
14560        window: &mut Window,
14561        cx: &mut Context<Self>,
14562    ) -> Result<()> {
14563        let selections = self.selections.disjoint_anchors();
14564        match selections.last() {
14565            Some(last) if selections.len() >= 2 => {
14566                self.change_selections(Default::default(), window, cx, |s| {
14567                    s.select_ranges([last.range()]);
14568                });
14569            }
14570            _ => self.select_previous(
14571                &SelectPrevious {
14572                    replace_newest: true,
14573                },
14574                window,
14575                cx,
14576            )?,
14577        }
14578        Ok(())
14579    }
14580
14581    pub fn toggle_comments(
14582        &mut self,
14583        action: &ToggleComments,
14584        window: &mut Window,
14585        cx: &mut Context<Self>,
14586    ) {
14587        if self.read_only(cx) {
14588            return;
14589        }
14590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14591        let text_layout_details = &self.text_layout_details(window);
14592        self.transact(window, cx, |this, window, cx| {
14593            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14594            let mut edits = Vec::new();
14595            let mut selection_edit_ranges = Vec::new();
14596            let mut last_toggled_row = None;
14597            let snapshot = this.buffer.read(cx).read(cx);
14598            let empty_str: Arc<str> = Arc::default();
14599            let mut suffixes_inserted = Vec::new();
14600            let ignore_indent = action.ignore_indent;
14601
14602            fn comment_prefix_range(
14603                snapshot: &MultiBufferSnapshot,
14604                row: MultiBufferRow,
14605                comment_prefix: &str,
14606                comment_prefix_whitespace: &str,
14607                ignore_indent: bool,
14608            ) -> Range<Point> {
14609                let indent_size = if ignore_indent {
14610                    0
14611                } else {
14612                    snapshot.indent_size_for_line(row).len
14613                };
14614
14615                let start = Point::new(row.0, indent_size);
14616
14617                let mut line_bytes = snapshot
14618                    .bytes_in_range(start..snapshot.max_point())
14619                    .flatten()
14620                    .copied();
14621
14622                // If this line currently begins with the line comment prefix, then record
14623                // the range containing the prefix.
14624                if line_bytes
14625                    .by_ref()
14626                    .take(comment_prefix.len())
14627                    .eq(comment_prefix.bytes())
14628                {
14629                    // Include any whitespace that matches the comment prefix.
14630                    let matching_whitespace_len = line_bytes
14631                        .zip(comment_prefix_whitespace.bytes())
14632                        .take_while(|(a, b)| a == b)
14633                        .count() as u32;
14634                    let end = Point::new(
14635                        start.row,
14636                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14637                    );
14638                    start..end
14639                } else {
14640                    start..start
14641                }
14642            }
14643
14644            fn comment_suffix_range(
14645                snapshot: &MultiBufferSnapshot,
14646                row: MultiBufferRow,
14647                comment_suffix: &str,
14648                comment_suffix_has_leading_space: bool,
14649            ) -> Range<Point> {
14650                let end = Point::new(row.0, snapshot.line_len(row));
14651                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14652
14653                let mut line_end_bytes = snapshot
14654                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14655                    .flatten()
14656                    .copied();
14657
14658                let leading_space_len = if suffix_start_column > 0
14659                    && line_end_bytes.next() == Some(b' ')
14660                    && comment_suffix_has_leading_space
14661                {
14662                    1
14663                } else {
14664                    0
14665                };
14666
14667                // If this line currently begins with the line comment prefix, then record
14668                // the range containing the prefix.
14669                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14670                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14671                    start..end
14672                } else {
14673                    end..end
14674                }
14675            }
14676
14677            // TODO: Handle selections that cross excerpts
14678            for selection in &mut selections {
14679                let start_column = snapshot
14680                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14681                    .len;
14682                let language = if let Some(language) =
14683                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14684                {
14685                    language
14686                } else {
14687                    continue;
14688                };
14689
14690                selection_edit_ranges.clear();
14691
14692                // If multiple selections contain a given row, avoid processing that
14693                // row more than once.
14694                let mut start_row = MultiBufferRow(selection.start.row);
14695                if last_toggled_row == Some(start_row) {
14696                    start_row = start_row.next_row();
14697                }
14698                let end_row =
14699                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14700                        MultiBufferRow(selection.end.row - 1)
14701                    } else {
14702                        MultiBufferRow(selection.end.row)
14703                    };
14704                last_toggled_row = Some(end_row);
14705
14706                if start_row > end_row {
14707                    continue;
14708                }
14709
14710                // If the language has line comments, toggle those.
14711                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14712
14713                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14714                if ignore_indent {
14715                    full_comment_prefixes = full_comment_prefixes
14716                        .into_iter()
14717                        .map(|s| Arc::from(s.trim_end()))
14718                        .collect();
14719                }
14720
14721                if !full_comment_prefixes.is_empty() {
14722                    let first_prefix = full_comment_prefixes
14723                        .first()
14724                        .expect("prefixes is non-empty");
14725                    let prefix_trimmed_lengths = full_comment_prefixes
14726                        .iter()
14727                        .map(|p| p.trim_end_matches(' ').len())
14728                        .collect::<SmallVec<[usize; 4]>>();
14729
14730                    let mut all_selection_lines_are_comments = true;
14731
14732                    for row in start_row.0..=end_row.0 {
14733                        let row = MultiBufferRow(row);
14734                        if start_row < end_row && snapshot.is_line_blank(row) {
14735                            continue;
14736                        }
14737
14738                        let prefix_range = full_comment_prefixes
14739                            .iter()
14740                            .zip(prefix_trimmed_lengths.iter().copied())
14741                            .map(|(prefix, trimmed_prefix_len)| {
14742                                comment_prefix_range(
14743                                    snapshot.deref(),
14744                                    row,
14745                                    &prefix[..trimmed_prefix_len],
14746                                    &prefix[trimmed_prefix_len..],
14747                                    ignore_indent,
14748                                )
14749                            })
14750                            .max_by_key(|range| range.end.column - range.start.column)
14751                            .expect("prefixes is non-empty");
14752
14753                        if prefix_range.is_empty() {
14754                            all_selection_lines_are_comments = false;
14755                        }
14756
14757                        selection_edit_ranges.push(prefix_range);
14758                    }
14759
14760                    if all_selection_lines_are_comments {
14761                        edits.extend(
14762                            selection_edit_ranges
14763                                .iter()
14764                                .cloned()
14765                                .map(|range| (range, empty_str.clone())),
14766                        );
14767                    } else {
14768                        let min_column = selection_edit_ranges
14769                            .iter()
14770                            .map(|range| range.start.column)
14771                            .min()
14772                            .unwrap_or(0);
14773                        edits.extend(selection_edit_ranges.iter().map(|range| {
14774                            let position = Point::new(range.start.row, min_column);
14775                            (position..position, first_prefix.clone())
14776                        }));
14777                    }
14778                } else if let Some(BlockCommentConfig {
14779                    start: full_comment_prefix,
14780                    end: comment_suffix,
14781                    ..
14782                }) = language.block_comment()
14783                {
14784                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14785                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14786                    let prefix_range = comment_prefix_range(
14787                        snapshot.deref(),
14788                        start_row,
14789                        comment_prefix,
14790                        comment_prefix_whitespace,
14791                        ignore_indent,
14792                    );
14793                    let suffix_range = comment_suffix_range(
14794                        snapshot.deref(),
14795                        end_row,
14796                        comment_suffix.trim_start_matches(' '),
14797                        comment_suffix.starts_with(' '),
14798                    );
14799
14800                    if prefix_range.is_empty() || suffix_range.is_empty() {
14801                        edits.push((
14802                            prefix_range.start..prefix_range.start,
14803                            full_comment_prefix.clone(),
14804                        ));
14805                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14806                        suffixes_inserted.push((end_row, comment_suffix.len()));
14807                    } else {
14808                        edits.push((prefix_range, empty_str.clone()));
14809                        edits.push((suffix_range, empty_str.clone()));
14810                    }
14811                } else {
14812                    continue;
14813                }
14814            }
14815
14816            drop(snapshot);
14817            this.buffer.update(cx, |buffer, cx| {
14818                buffer.edit(edits, None, cx);
14819            });
14820
14821            // Adjust selections so that they end before any comment suffixes that
14822            // were inserted.
14823            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14824            let mut selections = this.selections.all::<Point>(cx);
14825            let snapshot = this.buffer.read(cx).read(cx);
14826            for selection in &mut selections {
14827                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14828                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14829                        Ordering::Less => {
14830                            suffixes_inserted.next();
14831                            continue;
14832                        }
14833                        Ordering::Greater => break,
14834                        Ordering::Equal => {
14835                            if selection.end.column == snapshot.line_len(row) {
14836                                if selection.is_empty() {
14837                                    selection.start.column -= suffix_len as u32;
14838                                }
14839                                selection.end.column -= suffix_len as u32;
14840                            }
14841                            break;
14842                        }
14843                    }
14844                }
14845            }
14846
14847            drop(snapshot);
14848            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14849
14850            let selections = this.selections.all::<Point>(cx);
14851            let selections_on_single_row = selections.windows(2).all(|selections| {
14852                selections[0].start.row == selections[1].start.row
14853                    && selections[0].end.row == selections[1].end.row
14854                    && selections[0].start.row == selections[0].end.row
14855            });
14856            let selections_selecting = selections
14857                .iter()
14858                .any(|selection| selection.start != selection.end);
14859            let advance_downwards = action.advance_downwards
14860                && selections_on_single_row
14861                && !selections_selecting
14862                && !matches!(this.mode, EditorMode::SingleLine);
14863
14864            if advance_downwards {
14865                let snapshot = this.buffer.read(cx).snapshot(cx);
14866
14867                this.change_selections(Default::default(), window, cx, |s| {
14868                    s.move_cursors_with(|display_snapshot, display_point, _| {
14869                        let mut point = display_point.to_point(display_snapshot);
14870                        point.row += 1;
14871                        point = snapshot.clip_point(point, Bias::Left);
14872                        let display_point = point.to_display_point(display_snapshot);
14873                        let goal = SelectionGoal::HorizontalPosition(
14874                            display_snapshot
14875                                .x_for_display_point(display_point, text_layout_details)
14876                                .into(),
14877                        );
14878                        (display_point, goal)
14879                    })
14880                });
14881            }
14882        });
14883    }
14884
14885    pub fn select_enclosing_symbol(
14886        &mut self,
14887        _: &SelectEnclosingSymbol,
14888        window: &mut Window,
14889        cx: &mut Context<Self>,
14890    ) {
14891        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14892
14893        let buffer = self.buffer.read(cx).snapshot(cx);
14894        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14895
14896        fn update_selection(
14897            selection: &Selection<usize>,
14898            buffer_snap: &MultiBufferSnapshot,
14899        ) -> Option<Selection<usize>> {
14900            let cursor = selection.head();
14901            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14902            for symbol in symbols.iter().rev() {
14903                let start = symbol.range.start.to_offset(buffer_snap);
14904                let end = symbol.range.end.to_offset(buffer_snap);
14905                let new_range = start..end;
14906                if start < selection.start || end > selection.end {
14907                    return Some(Selection {
14908                        id: selection.id,
14909                        start: new_range.start,
14910                        end: new_range.end,
14911                        goal: SelectionGoal::None,
14912                        reversed: selection.reversed,
14913                    });
14914                }
14915            }
14916            None
14917        }
14918
14919        let mut selected_larger_symbol = false;
14920        let new_selections = old_selections
14921            .iter()
14922            .map(|selection| match update_selection(selection, &buffer) {
14923                Some(new_selection) => {
14924                    if new_selection.range() != selection.range() {
14925                        selected_larger_symbol = true;
14926                    }
14927                    new_selection
14928                }
14929                None => selection.clone(),
14930            })
14931            .collect::<Vec<_>>();
14932
14933        if selected_larger_symbol {
14934            self.change_selections(Default::default(), window, cx, |s| {
14935                s.select(new_selections);
14936            });
14937        }
14938    }
14939
14940    pub fn select_larger_syntax_node(
14941        &mut self,
14942        _: &SelectLargerSyntaxNode,
14943        window: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) {
14946        let Some(visible_row_count) = self.visible_row_count() else {
14947            return;
14948        };
14949        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14950        if old_selections.is_empty() {
14951            return;
14952        }
14953
14954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14955
14956        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14957        let buffer = self.buffer.read(cx).snapshot(cx);
14958
14959        let mut selected_larger_node = false;
14960        let mut new_selections = old_selections
14961            .iter()
14962            .map(|selection| {
14963                let old_range = selection.start..selection.end;
14964
14965                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14966                    // manually select word at selection
14967                    if ["string_content", "inline"].contains(&node.kind()) {
14968                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14969                        // ignore if word is already selected
14970                        if !word_range.is_empty() && old_range != word_range {
14971                            let (last_word_range, _) =
14972                                buffer.surrounding_word(old_range.end, false);
14973                            // only select word if start and end point belongs to same word
14974                            if word_range == last_word_range {
14975                                selected_larger_node = true;
14976                                return Selection {
14977                                    id: selection.id,
14978                                    start: word_range.start,
14979                                    end: word_range.end,
14980                                    goal: SelectionGoal::None,
14981                                    reversed: selection.reversed,
14982                                };
14983                            }
14984                        }
14985                    }
14986                }
14987
14988                let mut new_range = old_range.clone();
14989                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14990                {
14991                    if !node.is_named() {
14992                        new_range = node.start_byte()..node.end_byte();
14993                        continue;
14994                    }
14995
14996                    new_range = match containing_range {
14997                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14998                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14999                    };
15000                    if !display_map.intersects_fold(new_range.start)
15001                        && !display_map.intersects_fold(new_range.end)
15002                    {
15003                        break;
15004                    }
15005                }
15006
15007                selected_larger_node |= new_range != old_range;
15008                Selection {
15009                    id: selection.id,
15010                    start: new_range.start,
15011                    end: new_range.end,
15012                    goal: SelectionGoal::None,
15013                    reversed: selection.reversed,
15014                }
15015            })
15016            .collect::<Vec<_>>();
15017
15018        if !selected_larger_node {
15019            return; // don't put this call in the history
15020        }
15021
15022        // scroll based on transformation done to the last selection created by the user
15023        let (last_old, last_new) = old_selections
15024            .last()
15025            .zip(new_selections.last().cloned())
15026            .expect("old_selections isn't empty");
15027
15028        // revert selection
15029        let is_selection_reversed = {
15030            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15031            new_selections.last_mut().expect("checked above").reversed =
15032                should_newest_selection_be_reversed;
15033            should_newest_selection_be_reversed
15034        };
15035
15036        if selected_larger_node {
15037            self.select_syntax_node_history.disable_clearing = true;
15038            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15039                s.select(new_selections.clone());
15040            });
15041            self.select_syntax_node_history.disable_clearing = false;
15042        }
15043
15044        let start_row = last_new.start.to_display_point(&display_map).row().0;
15045        let end_row = last_new.end.to_display_point(&display_map).row().0;
15046        let selection_height = end_row - start_row + 1;
15047        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15048
15049        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15050        let scroll_behavior = if fits_on_the_screen {
15051            self.request_autoscroll(Autoscroll::fit(), cx);
15052            SelectSyntaxNodeScrollBehavior::FitSelection
15053        } else if is_selection_reversed {
15054            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15055            SelectSyntaxNodeScrollBehavior::CursorTop
15056        } else {
15057            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15058            SelectSyntaxNodeScrollBehavior::CursorBottom
15059        };
15060
15061        self.select_syntax_node_history.push((
15062            old_selections,
15063            scroll_behavior,
15064            is_selection_reversed,
15065        ));
15066    }
15067
15068    pub fn select_smaller_syntax_node(
15069        &mut self,
15070        _: &SelectSmallerSyntaxNode,
15071        window: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15075
15076        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15077            self.select_syntax_node_history.pop()
15078        {
15079            if let Some(selection) = selections.last_mut() {
15080                selection.reversed = is_selection_reversed;
15081            }
15082
15083            self.select_syntax_node_history.disable_clearing = true;
15084            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15085                s.select(selections.to_vec());
15086            });
15087            self.select_syntax_node_history.disable_clearing = false;
15088
15089            match scroll_behavior {
15090                SelectSyntaxNodeScrollBehavior::CursorTop => {
15091                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15092                }
15093                SelectSyntaxNodeScrollBehavior::FitSelection => {
15094                    self.request_autoscroll(Autoscroll::fit(), cx);
15095                }
15096                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15097                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15098                }
15099            }
15100        }
15101    }
15102
15103    pub fn unwrap_syntax_node(
15104        &mut self,
15105        _: &UnwrapSyntaxNode,
15106        window: &mut Window,
15107        cx: &mut Context<Self>,
15108    ) {
15109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15110
15111        let buffer = self.buffer.read(cx).snapshot(cx);
15112        let selections = self
15113            .selections
15114            .all::<usize>(cx)
15115            .into_iter()
15116            // subtracting the offset requires sorting
15117            .sorted_by_key(|i| i.start);
15118
15119        let full_edits = selections
15120            .into_iter()
15121            .filter_map(|selection| {
15122                // Only requires two branches once if-let-chains stabilize (#53667)
15123                let child = if !selection.is_empty() {
15124                    selection.range()
15125                } else if let Some((_, ancestor_range)) =
15126                    buffer.syntax_ancestor(selection.start..selection.end)
15127                {
15128                    match ancestor_range {
15129                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15130                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15131                    }
15132                } else {
15133                    selection.range()
15134                };
15135
15136                let mut parent = child.clone();
15137                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15138                    parent = match ancestor_range {
15139                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15140                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15141                    };
15142                    if parent.start < child.start || parent.end > child.end {
15143                        break;
15144                    }
15145                }
15146
15147                if parent == child {
15148                    return None;
15149                }
15150                let text = buffer.text_for_range(child).collect::<String>();
15151                Some((selection.id, parent, text))
15152            })
15153            .collect::<Vec<_>>();
15154
15155        self.transact(window, cx, |this, window, cx| {
15156            this.buffer.update(cx, |buffer, cx| {
15157                buffer.edit(
15158                    full_edits
15159                        .iter()
15160                        .map(|(_, p, t)| (p.clone(), t.clone()))
15161                        .collect::<Vec<_>>(),
15162                    None,
15163                    cx,
15164                );
15165            });
15166            this.change_selections(Default::default(), window, cx, |s| {
15167                let mut offset = 0;
15168                let mut selections = vec![];
15169                for (id, parent, text) in full_edits {
15170                    let start = parent.start - offset;
15171                    offset += parent.len() - text.len();
15172                    selections.push(Selection {
15173                        id,
15174                        start,
15175                        end: start + text.len(),
15176                        reversed: false,
15177                        goal: Default::default(),
15178                    });
15179                }
15180                s.select(selections);
15181            });
15182        });
15183    }
15184
15185    pub fn select_next_syntax_node(
15186        &mut self,
15187        _: &SelectNextSyntaxNode,
15188        window: &mut Window,
15189        cx: &mut Context<Self>,
15190    ) {
15191        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15192        if old_selections.is_empty() {
15193            return;
15194        }
15195
15196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15197
15198        let buffer = self.buffer.read(cx).snapshot(cx);
15199        let mut selected_sibling = false;
15200
15201        let new_selections = old_selections
15202            .iter()
15203            .map(|selection| {
15204                let old_range = selection.start..selection.end;
15205
15206                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15207                    let new_range = node.byte_range();
15208                    selected_sibling = true;
15209                    Selection {
15210                        id: selection.id,
15211                        start: new_range.start,
15212                        end: new_range.end,
15213                        goal: SelectionGoal::None,
15214                        reversed: selection.reversed,
15215                    }
15216                } else {
15217                    selection.clone()
15218                }
15219            })
15220            .collect::<Vec<_>>();
15221
15222        if selected_sibling {
15223            self.change_selections(
15224                SelectionEffects::scroll(Autoscroll::fit()),
15225                window,
15226                cx,
15227                |s| {
15228                    s.select(new_selections);
15229                },
15230            );
15231        }
15232    }
15233
15234    pub fn select_prev_syntax_node(
15235        &mut self,
15236        _: &SelectPreviousSyntaxNode,
15237        window: &mut Window,
15238        cx: &mut Context<Self>,
15239    ) {
15240        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15241        if old_selections.is_empty() {
15242            return;
15243        }
15244
15245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15246
15247        let buffer = self.buffer.read(cx).snapshot(cx);
15248        let mut selected_sibling = false;
15249
15250        let new_selections = old_selections
15251            .iter()
15252            .map(|selection| {
15253                let old_range = selection.start..selection.end;
15254
15255                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15256                    let new_range = node.byte_range();
15257                    selected_sibling = true;
15258                    Selection {
15259                        id: selection.id,
15260                        start: new_range.start,
15261                        end: new_range.end,
15262                        goal: SelectionGoal::None,
15263                        reversed: selection.reversed,
15264                    }
15265                } else {
15266                    selection.clone()
15267                }
15268            })
15269            .collect::<Vec<_>>();
15270
15271        if selected_sibling {
15272            self.change_selections(
15273                SelectionEffects::scroll(Autoscroll::fit()),
15274                window,
15275                cx,
15276                |s| {
15277                    s.select(new_selections);
15278                },
15279            );
15280        }
15281    }
15282
15283    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15284        if !EditorSettings::get_global(cx).gutter.runnables {
15285            self.clear_tasks();
15286            return Task::ready(());
15287        }
15288        let project = self.project().map(Entity::downgrade);
15289        let task_sources = self.lsp_task_sources(cx);
15290        let multi_buffer = self.buffer.downgrade();
15291        cx.spawn_in(window, async move |editor, cx| {
15292            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15293            let Some(project) = project.and_then(|p| p.upgrade()) else {
15294                return;
15295            };
15296            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15297                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15298            }) else {
15299                return;
15300            };
15301
15302            let hide_runnables = project
15303                .update(cx, |project, _| project.is_via_collab())
15304                .unwrap_or(true);
15305            if hide_runnables {
15306                return;
15307            }
15308            let new_rows =
15309                cx.background_spawn({
15310                    let snapshot = display_snapshot.clone();
15311                    async move {
15312                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15313                    }
15314                })
15315                    .await;
15316            let Ok(lsp_tasks) =
15317                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15318            else {
15319                return;
15320            };
15321            let lsp_tasks = lsp_tasks.await;
15322
15323            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15324                lsp_tasks
15325                    .into_iter()
15326                    .flat_map(|(kind, tasks)| {
15327                        tasks.into_iter().filter_map(move |(location, task)| {
15328                            Some((kind.clone(), location?, task))
15329                        })
15330                    })
15331                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15332                        let buffer = location.target.buffer;
15333                        let buffer_snapshot = buffer.read(cx).snapshot();
15334                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15335                            |(excerpt_id, snapshot, _)| {
15336                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15337                                    display_snapshot
15338                                        .buffer_snapshot
15339                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15340                                } else {
15341                                    None
15342                                }
15343                            },
15344                        );
15345                        if let Some(offset) = offset {
15346                            let task_buffer_range =
15347                                location.target.range.to_point(&buffer_snapshot);
15348                            let context_buffer_range =
15349                                task_buffer_range.to_offset(&buffer_snapshot);
15350                            let context_range = BufferOffset(context_buffer_range.start)
15351                                ..BufferOffset(context_buffer_range.end);
15352
15353                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15354                                .or_insert_with(|| RunnableTasks {
15355                                    templates: Vec::new(),
15356                                    offset,
15357                                    column: task_buffer_range.start.column,
15358                                    extra_variables: HashMap::default(),
15359                                    context_range,
15360                                })
15361                                .templates
15362                                .push((kind, task.original_task().clone()));
15363                        }
15364
15365                        acc
15366                    })
15367            }) else {
15368                return;
15369            };
15370
15371            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15372                buffer.language_settings(cx).tasks.prefer_lsp
15373            }) else {
15374                return;
15375            };
15376
15377            let rows = Self::runnable_rows(
15378                project,
15379                display_snapshot,
15380                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15381                new_rows,
15382                cx.clone(),
15383            )
15384            .await;
15385            editor
15386                .update(cx, |editor, _| {
15387                    editor.clear_tasks();
15388                    for (key, mut value) in rows {
15389                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15390                            value.templates.extend(lsp_tasks.templates);
15391                        }
15392
15393                        editor.insert_tasks(key, value);
15394                    }
15395                    for (key, value) in lsp_tasks_by_rows {
15396                        editor.insert_tasks(key, value);
15397                    }
15398                })
15399                .ok();
15400        })
15401    }
15402    fn fetch_runnable_ranges(
15403        snapshot: &DisplaySnapshot,
15404        range: Range<Anchor>,
15405    ) -> Vec<language::RunnableRange> {
15406        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15407    }
15408
15409    fn runnable_rows(
15410        project: Entity<Project>,
15411        snapshot: DisplaySnapshot,
15412        prefer_lsp: bool,
15413        runnable_ranges: Vec<RunnableRange>,
15414        cx: AsyncWindowContext,
15415    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15416        cx.spawn(async move |cx| {
15417            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15418            for mut runnable in runnable_ranges {
15419                let Some(tasks) = cx
15420                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15421                    .ok()
15422                else {
15423                    continue;
15424                };
15425                let mut tasks = tasks.await;
15426
15427                if prefer_lsp {
15428                    tasks.retain(|(task_kind, _)| {
15429                        !matches!(task_kind, TaskSourceKind::Language { .. })
15430                    });
15431                }
15432                if tasks.is_empty() {
15433                    continue;
15434                }
15435
15436                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15437                let Some(row) = snapshot
15438                    .buffer_snapshot
15439                    .buffer_line_for_row(MultiBufferRow(point.row))
15440                    .map(|(_, range)| range.start.row)
15441                else {
15442                    continue;
15443                };
15444
15445                let context_range =
15446                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15447                runnable_rows.push((
15448                    (runnable.buffer_id, row),
15449                    RunnableTasks {
15450                        templates: tasks,
15451                        offset: snapshot
15452                            .buffer_snapshot
15453                            .anchor_before(runnable.run_range.start),
15454                        context_range,
15455                        column: point.column,
15456                        extra_variables: runnable.extra_captures,
15457                    },
15458                ));
15459            }
15460            runnable_rows
15461        })
15462    }
15463
15464    fn templates_with_tags(
15465        project: &Entity<Project>,
15466        runnable: &mut Runnable,
15467        cx: &mut App,
15468    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15469        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15470            let (worktree_id, file) = project
15471                .buffer_for_id(runnable.buffer, cx)
15472                .and_then(|buffer| buffer.read(cx).file())
15473                .map(|file| (file.worktree_id(cx), file.clone()))
15474                .unzip();
15475
15476            (
15477                project.task_store().read(cx).task_inventory().cloned(),
15478                worktree_id,
15479                file,
15480            )
15481        });
15482
15483        let tags = mem::take(&mut runnable.tags);
15484        let language = runnable.language.clone();
15485        cx.spawn(async move |cx| {
15486            let mut templates_with_tags = Vec::new();
15487            if let Some(inventory) = inventory {
15488                for RunnableTag(tag) in tags {
15489                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15490                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15491                    }) else {
15492                        return templates_with_tags;
15493                    };
15494                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15495                        move |(_, template)| {
15496                            template.tags.iter().any(|source_tag| source_tag == &tag)
15497                        },
15498                    ));
15499                }
15500            }
15501            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15502
15503            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15504                // Strongest source wins; if we have worktree tag binding, prefer that to
15505                // global and language bindings;
15506                // if we have a global binding, prefer that to language binding.
15507                let first_mismatch = templates_with_tags
15508                    .iter()
15509                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15510                if let Some(index) = first_mismatch {
15511                    templates_with_tags.truncate(index);
15512                }
15513            }
15514
15515            templates_with_tags
15516        })
15517    }
15518
15519    pub fn move_to_enclosing_bracket(
15520        &mut self,
15521        _: &MoveToEnclosingBracket,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) {
15525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15526        self.change_selections(Default::default(), window, cx, |s| {
15527            s.move_offsets_with(|snapshot, selection| {
15528                let Some(enclosing_bracket_ranges) =
15529                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15530                else {
15531                    return;
15532                };
15533
15534                let mut best_length = usize::MAX;
15535                let mut best_inside = false;
15536                let mut best_in_bracket_range = false;
15537                let mut best_destination = None;
15538                for (open, close) in enclosing_bracket_ranges {
15539                    let close = close.to_inclusive();
15540                    let length = close.end() - open.start;
15541                    let inside = selection.start >= open.end && selection.end <= *close.start();
15542                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15543                        || close.contains(&selection.head());
15544
15545                    // If best is next to a bracket and current isn't, skip
15546                    if !in_bracket_range && best_in_bracket_range {
15547                        continue;
15548                    }
15549
15550                    // Prefer smaller lengths unless best is inside and current isn't
15551                    if length > best_length && (best_inside || !inside) {
15552                        continue;
15553                    }
15554
15555                    best_length = length;
15556                    best_inside = inside;
15557                    best_in_bracket_range = in_bracket_range;
15558                    best_destination = Some(
15559                        if close.contains(&selection.start) && close.contains(&selection.end) {
15560                            if inside { open.end } else { open.start }
15561                        } else if inside {
15562                            *close.start()
15563                        } else {
15564                            *close.end()
15565                        },
15566                    );
15567                }
15568
15569                if let Some(destination) = best_destination {
15570                    selection.collapse_to(destination, SelectionGoal::None);
15571                }
15572            })
15573        });
15574    }
15575
15576    pub fn undo_selection(
15577        &mut self,
15578        _: &UndoSelection,
15579        window: &mut Window,
15580        cx: &mut Context<Self>,
15581    ) {
15582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15583        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15584            self.selection_history.mode = SelectionHistoryMode::Undoing;
15585            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15586                this.end_selection(window, cx);
15587                this.change_selections(
15588                    SelectionEffects::scroll(Autoscroll::newest()),
15589                    window,
15590                    cx,
15591                    |s| s.select_anchors(entry.selections.to_vec()),
15592                );
15593            });
15594            self.selection_history.mode = SelectionHistoryMode::Normal;
15595
15596            self.select_next_state = entry.select_next_state;
15597            self.select_prev_state = entry.select_prev_state;
15598            self.add_selections_state = entry.add_selections_state;
15599        }
15600    }
15601
15602    pub fn redo_selection(
15603        &mut self,
15604        _: &RedoSelection,
15605        window: &mut Window,
15606        cx: &mut Context<Self>,
15607    ) {
15608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15609        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15610            self.selection_history.mode = SelectionHistoryMode::Redoing;
15611            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15612                this.end_selection(window, cx);
15613                this.change_selections(
15614                    SelectionEffects::scroll(Autoscroll::newest()),
15615                    window,
15616                    cx,
15617                    |s| s.select_anchors(entry.selections.to_vec()),
15618                );
15619            });
15620            self.selection_history.mode = SelectionHistoryMode::Normal;
15621
15622            self.select_next_state = entry.select_next_state;
15623            self.select_prev_state = entry.select_prev_state;
15624            self.add_selections_state = entry.add_selections_state;
15625        }
15626    }
15627
15628    pub fn expand_excerpts(
15629        &mut self,
15630        action: &ExpandExcerpts,
15631        _: &mut Window,
15632        cx: &mut Context<Self>,
15633    ) {
15634        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15635    }
15636
15637    pub fn expand_excerpts_down(
15638        &mut self,
15639        action: &ExpandExcerptsDown,
15640        _: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15644    }
15645
15646    pub fn expand_excerpts_up(
15647        &mut self,
15648        action: &ExpandExcerptsUp,
15649        _: &mut Window,
15650        cx: &mut Context<Self>,
15651    ) {
15652        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15653    }
15654
15655    pub fn expand_excerpts_for_direction(
15656        &mut self,
15657        lines: u32,
15658        direction: ExpandExcerptDirection,
15659
15660        cx: &mut Context<Self>,
15661    ) {
15662        let selections = self.selections.disjoint_anchors();
15663
15664        let lines = if lines == 0 {
15665            EditorSettings::get_global(cx).expand_excerpt_lines
15666        } else {
15667            lines
15668        };
15669
15670        self.buffer.update(cx, |buffer, cx| {
15671            let snapshot = buffer.snapshot(cx);
15672            let mut excerpt_ids = selections
15673                .iter()
15674                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15675                .collect::<Vec<_>>();
15676            excerpt_ids.sort();
15677            excerpt_ids.dedup();
15678            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15679        })
15680    }
15681
15682    pub fn expand_excerpt(
15683        &mut self,
15684        excerpt: ExcerptId,
15685        direction: ExpandExcerptDirection,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) {
15689        let current_scroll_position = self.scroll_position(cx);
15690        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15691        let mut should_scroll_up = false;
15692
15693        if direction == ExpandExcerptDirection::Down {
15694            let multi_buffer = self.buffer.read(cx);
15695            let snapshot = multi_buffer.snapshot(cx);
15696            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15697                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15698                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15699            {
15700                let buffer_snapshot = buffer.read(cx).snapshot();
15701                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15702                let last_row = buffer_snapshot.max_point().row;
15703                let lines_below = last_row.saturating_sub(excerpt_end_row);
15704                should_scroll_up = lines_below >= lines_to_expand;
15705            }
15706        }
15707
15708        self.buffer.update(cx, |buffer, cx| {
15709            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15710        });
15711
15712        if should_scroll_up {
15713            let new_scroll_position =
15714                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15715            self.set_scroll_position(new_scroll_position, window, cx);
15716        }
15717    }
15718
15719    pub fn go_to_singleton_buffer_point(
15720        &mut self,
15721        point: Point,
15722        window: &mut Window,
15723        cx: &mut Context<Self>,
15724    ) {
15725        self.go_to_singleton_buffer_range(point..point, window, cx);
15726    }
15727
15728    pub fn go_to_singleton_buffer_range(
15729        &mut self,
15730        range: Range<Point>,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) {
15734        let multibuffer = self.buffer().read(cx);
15735        let Some(buffer) = multibuffer.as_singleton() else {
15736            return;
15737        };
15738        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15739            return;
15740        };
15741        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15742            return;
15743        };
15744        self.change_selections(
15745            SelectionEffects::default().nav_history(true),
15746            window,
15747            cx,
15748            |s| s.select_anchor_ranges([start..end]),
15749        );
15750    }
15751
15752    pub fn go_to_diagnostic(
15753        &mut self,
15754        action: &GoToDiagnostic,
15755        window: &mut Window,
15756        cx: &mut Context<Self>,
15757    ) {
15758        if !self.diagnostics_enabled() {
15759            return;
15760        }
15761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15762        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15763    }
15764
15765    pub fn go_to_prev_diagnostic(
15766        &mut self,
15767        action: &GoToPreviousDiagnostic,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) {
15771        if !self.diagnostics_enabled() {
15772            return;
15773        }
15774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15775        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15776    }
15777
15778    pub fn go_to_diagnostic_impl(
15779        &mut self,
15780        direction: Direction,
15781        severity: GoToDiagnosticSeverityFilter,
15782        window: &mut Window,
15783        cx: &mut Context<Self>,
15784    ) {
15785        let buffer = self.buffer.read(cx).snapshot(cx);
15786        let selection = self.selections.newest::<usize>(cx);
15787
15788        let mut active_group_id = None;
15789        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15790            && active_group.active_range.start.to_offset(&buffer) == selection.start
15791        {
15792            active_group_id = Some(active_group.group_id);
15793        }
15794
15795        fn filtered(
15796            snapshot: EditorSnapshot,
15797            severity: GoToDiagnosticSeverityFilter,
15798            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15799        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15800            diagnostics
15801                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15802                .filter(|entry| entry.range.start != entry.range.end)
15803                .filter(|entry| !entry.diagnostic.is_unnecessary)
15804                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15805        }
15806
15807        let snapshot = self.snapshot(window, cx);
15808        let before = filtered(
15809            snapshot.clone(),
15810            severity,
15811            buffer
15812                .diagnostics_in_range(0..selection.start)
15813                .filter(|entry| entry.range.start <= selection.start),
15814        );
15815        let after = filtered(
15816            snapshot,
15817            severity,
15818            buffer
15819                .diagnostics_in_range(selection.start..buffer.len())
15820                .filter(|entry| entry.range.start >= selection.start),
15821        );
15822
15823        let mut found: Option<DiagnosticEntry<usize>> = None;
15824        if direction == Direction::Prev {
15825            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15826            {
15827                for diagnostic in prev_diagnostics.into_iter().rev() {
15828                    if diagnostic.range.start != selection.start
15829                        || active_group_id
15830                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15831                    {
15832                        found = Some(diagnostic);
15833                        break 'outer;
15834                    }
15835                }
15836            }
15837        } else {
15838            for diagnostic in after.chain(before) {
15839                if diagnostic.range.start != selection.start
15840                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15841                {
15842                    found = Some(diagnostic);
15843                    break;
15844                }
15845            }
15846        }
15847        let Some(next_diagnostic) = found else {
15848            return;
15849        };
15850
15851        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15852        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15853            return;
15854        };
15855        self.change_selections(Default::default(), window, cx, |s| {
15856            s.select_ranges(vec![
15857                next_diagnostic.range.start..next_diagnostic.range.start,
15858            ])
15859        });
15860        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15861        self.refresh_edit_prediction(false, true, window, cx);
15862    }
15863
15864    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15866        let snapshot = self.snapshot(window, cx);
15867        let selection = self.selections.newest::<Point>(cx);
15868        self.go_to_hunk_before_or_after_position(
15869            &snapshot,
15870            selection.head(),
15871            Direction::Next,
15872            window,
15873            cx,
15874        );
15875    }
15876
15877    pub fn go_to_hunk_before_or_after_position(
15878        &mut self,
15879        snapshot: &EditorSnapshot,
15880        position: Point,
15881        direction: Direction,
15882        window: &mut Window,
15883        cx: &mut Context<Editor>,
15884    ) {
15885        let row = if direction == Direction::Next {
15886            self.hunk_after_position(snapshot, position)
15887                .map(|hunk| hunk.row_range.start)
15888        } else {
15889            self.hunk_before_position(snapshot, position)
15890        };
15891
15892        if let Some(row) = row {
15893            let destination = Point::new(row.0, 0);
15894            let autoscroll = Autoscroll::center();
15895
15896            self.unfold_ranges(&[destination..destination], false, false, cx);
15897            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15898                s.select_ranges([destination..destination]);
15899            });
15900        }
15901    }
15902
15903    fn hunk_after_position(
15904        &mut self,
15905        snapshot: &EditorSnapshot,
15906        position: Point,
15907    ) -> Option<MultiBufferDiffHunk> {
15908        snapshot
15909            .buffer_snapshot
15910            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15911            .find(|hunk| hunk.row_range.start.0 > position.row)
15912            .or_else(|| {
15913                snapshot
15914                    .buffer_snapshot
15915                    .diff_hunks_in_range(Point::zero()..position)
15916                    .find(|hunk| hunk.row_range.end.0 < position.row)
15917            })
15918    }
15919
15920    fn go_to_prev_hunk(
15921        &mut self,
15922        _: &GoToPreviousHunk,
15923        window: &mut Window,
15924        cx: &mut Context<Self>,
15925    ) {
15926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15927        let snapshot = self.snapshot(window, cx);
15928        let selection = self.selections.newest::<Point>(cx);
15929        self.go_to_hunk_before_or_after_position(
15930            &snapshot,
15931            selection.head(),
15932            Direction::Prev,
15933            window,
15934            cx,
15935        );
15936    }
15937
15938    fn hunk_before_position(
15939        &mut self,
15940        snapshot: &EditorSnapshot,
15941        position: Point,
15942    ) -> Option<MultiBufferRow> {
15943        snapshot
15944            .buffer_snapshot
15945            .diff_hunk_before(position)
15946            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15947    }
15948
15949    fn go_to_next_change(
15950        &mut self,
15951        _: &GoToNextChange,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        if let Some(selections) = self
15956            .change_list
15957            .next_change(1, Direction::Next)
15958            .map(|s| s.to_vec())
15959        {
15960            self.change_selections(Default::default(), window, cx, |s| {
15961                let map = s.display_map();
15962                s.select_display_ranges(selections.iter().map(|a| {
15963                    let point = a.to_display_point(&map);
15964                    point..point
15965                }))
15966            })
15967        }
15968    }
15969
15970    fn go_to_previous_change(
15971        &mut self,
15972        _: &GoToPreviousChange,
15973        window: &mut Window,
15974        cx: &mut Context<Self>,
15975    ) {
15976        if let Some(selections) = self
15977            .change_list
15978            .next_change(1, Direction::Prev)
15979            .map(|s| s.to_vec())
15980        {
15981            self.change_selections(Default::default(), window, cx, |s| {
15982                let map = s.display_map();
15983                s.select_display_ranges(selections.iter().map(|a| {
15984                    let point = a.to_display_point(&map);
15985                    point..point
15986                }))
15987            })
15988        }
15989    }
15990
15991    pub fn go_to_next_document_highlight(
15992        &mut self,
15993        _: &GoToNextDocumentHighlight,
15994        window: &mut Window,
15995        cx: &mut Context<Self>,
15996    ) {
15997        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
15998    }
15999
16000    pub fn go_to_prev_document_highlight(
16001        &mut self,
16002        _: &GoToPreviousDocumentHighlight,
16003        window: &mut Window,
16004        cx: &mut Context<Self>,
16005    ) {
16006        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16007    }
16008
16009    pub fn go_to_document_highlight_before_or_after_position(
16010        &mut self,
16011        direction: Direction,
16012        window: &mut Window,
16013        cx: &mut Context<Editor>,
16014    ) {
16015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16016        let snapshot = self.snapshot(window, cx);
16017        let buffer = &snapshot.buffer_snapshot;
16018        let position = self.selections.newest::<Point>(cx).head();
16019        let anchor_position = buffer.anchor_after(position);
16020
16021        // Get all document highlights (both read and write)
16022        let mut all_highlights = Vec::new();
16023
16024        if let Some((_, read_highlights)) = self
16025            .background_highlights
16026            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16027        {
16028            all_highlights.extend(read_highlights.iter());
16029        }
16030
16031        if let Some((_, write_highlights)) = self
16032            .background_highlights
16033            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16034        {
16035            all_highlights.extend(write_highlights.iter());
16036        }
16037
16038        if all_highlights.is_empty() {
16039            return;
16040        }
16041
16042        // Sort highlights by position
16043        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16044
16045        let target_highlight = match direction {
16046            Direction::Next => {
16047                // Find the first highlight after the current position
16048                all_highlights
16049                    .iter()
16050                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16051            }
16052            Direction::Prev => {
16053                // Find the last highlight before the current position
16054                all_highlights
16055                    .iter()
16056                    .rev()
16057                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16058            }
16059        };
16060
16061        if let Some(highlight) = target_highlight {
16062            let destination = highlight.start.to_point(buffer);
16063            let autoscroll = Autoscroll::center();
16064
16065            self.unfold_ranges(&[destination..destination], false, false, cx);
16066            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16067                s.select_ranges([destination..destination]);
16068            });
16069        }
16070    }
16071
16072    fn go_to_line<T: 'static>(
16073        &mut self,
16074        position: Anchor,
16075        highlight_color: Option<Hsla>,
16076        window: &mut Window,
16077        cx: &mut Context<Self>,
16078    ) {
16079        let snapshot = self.snapshot(window, cx).display_snapshot;
16080        let position = position.to_point(&snapshot.buffer_snapshot);
16081        let start = snapshot
16082            .buffer_snapshot
16083            .clip_point(Point::new(position.row, 0), Bias::Left);
16084        let end = start + Point::new(1, 0);
16085        let start = snapshot.buffer_snapshot.anchor_before(start);
16086        let end = snapshot.buffer_snapshot.anchor_before(end);
16087
16088        self.highlight_rows::<T>(
16089            start..end,
16090            highlight_color
16091                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16092            Default::default(),
16093            cx,
16094        );
16095
16096        if self.buffer.read(cx).is_singleton() {
16097            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16098        }
16099    }
16100
16101    pub fn go_to_definition(
16102        &mut self,
16103        _: &GoToDefinition,
16104        window: &mut Window,
16105        cx: &mut Context<Self>,
16106    ) -> Task<Result<Navigated>> {
16107        let definition =
16108            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16109        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16110        cx.spawn_in(window, async move |editor, cx| {
16111            if definition.await? == Navigated::Yes {
16112                return Ok(Navigated::Yes);
16113            }
16114            match fallback_strategy {
16115                GoToDefinitionFallback::None => Ok(Navigated::No),
16116                GoToDefinitionFallback::FindAllReferences => {
16117                    match editor.update_in(cx, |editor, window, cx| {
16118                        editor.find_all_references(&FindAllReferences, window, cx)
16119                    })? {
16120                        Some(references) => references.await,
16121                        None => Ok(Navigated::No),
16122                    }
16123                }
16124            }
16125        })
16126    }
16127
16128    pub fn go_to_declaration(
16129        &mut self,
16130        _: &GoToDeclaration,
16131        window: &mut Window,
16132        cx: &mut Context<Self>,
16133    ) -> Task<Result<Navigated>> {
16134        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16135    }
16136
16137    pub fn go_to_declaration_split(
16138        &mut self,
16139        _: &GoToDeclaration,
16140        window: &mut Window,
16141        cx: &mut Context<Self>,
16142    ) -> Task<Result<Navigated>> {
16143        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16144    }
16145
16146    pub fn go_to_implementation(
16147        &mut self,
16148        _: &GoToImplementation,
16149        window: &mut Window,
16150        cx: &mut Context<Self>,
16151    ) -> Task<Result<Navigated>> {
16152        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16153    }
16154
16155    pub fn go_to_implementation_split(
16156        &mut self,
16157        _: &GoToImplementationSplit,
16158        window: &mut Window,
16159        cx: &mut Context<Self>,
16160    ) -> Task<Result<Navigated>> {
16161        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16162    }
16163
16164    pub fn go_to_type_definition(
16165        &mut self,
16166        _: &GoToTypeDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16171    }
16172
16173    pub fn go_to_definition_split(
16174        &mut self,
16175        _: &GoToDefinitionSplit,
16176        window: &mut Window,
16177        cx: &mut Context<Self>,
16178    ) -> Task<Result<Navigated>> {
16179        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16180    }
16181
16182    pub fn go_to_type_definition_split(
16183        &mut self,
16184        _: &GoToTypeDefinitionSplit,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) -> Task<Result<Navigated>> {
16188        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16189    }
16190
16191    fn go_to_definition_of_kind(
16192        &mut self,
16193        kind: GotoDefinitionKind,
16194        split: bool,
16195        window: &mut Window,
16196        cx: &mut Context<Self>,
16197    ) -> Task<Result<Navigated>> {
16198        let Some(provider) = self.semantics_provider.clone() else {
16199            return Task::ready(Ok(Navigated::No));
16200        };
16201        let head = self.selections.newest::<usize>(cx).head();
16202        let buffer = self.buffer.read(cx);
16203        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16204            return Task::ready(Ok(Navigated::No));
16205        };
16206        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16207            return Task::ready(Ok(Navigated::No));
16208        };
16209
16210        cx.spawn_in(window, async move |editor, cx| {
16211            let Some(definitions) = definitions.await? else {
16212                return Ok(Navigated::No);
16213            };
16214            let navigated = editor
16215                .update_in(cx, |editor, window, cx| {
16216                    editor.navigate_to_hover_links(
16217                        Some(kind),
16218                        definitions
16219                            .into_iter()
16220                            .filter(|location| {
16221                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16222                            })
16223                            .map(HoverLink::Text)
16224                            .collect::<Vec<_>>(),
16225                        split,
16226                        window,
16227                        cx,
16228                    )
16229                })?
16230                .await?;
16231            anyhow::Ok(navigated)
16232        })
16233    }
16234
16235    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16236        let selection = self.selections.newest_anchor();
16237        let head = selection.head();
16238        let tail = selection.tail();
16239
16240        let Some((buffer, start_position)) =
16241            self.buffer.read(cx).text_anchor_for_position(head, cx)
16242        else {
16243            return;
16244        };
16245
16246        let end_position = if head != tail {
16247            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16248                return;
16249            };
16250            Some(pos)
16251        } else {
16252            None
16253        };
16254
16255        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16256            let url = if let Some(end_pos) = end_position {
16257                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16258            } else {
16259                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16260            };
16261
16262            if let Some(url) = url {
16263                editor.update(cx, |_, cx| {
16264                    cx.open_url(&url);
16265                })
16266            } else {
16267                Ok(())
16268            }
16269        });
16270
16271        url_finder.detach();
16272    }
16273
16274    pub fn open_selected_filename(
16275        &mut self,
16276        _: &OpenSelectedFilename,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        let Some(workspace) = self.workspace() else {
16281            return;
16282        };
16283
16284        let position = self.selections.newest_anchor().head();
16285
16286        let Some((buffer, buffer_position)) =
16287            self.buffer.read(cx).text_anchor_for_position(position, cx)
16288        else {
16289            return;
16290        };
16291
16292        let project = self.project.clone();
16293
16294        cx.spawn_in(window, async move |_, cx| {
16295            let result = find_file(&buffer, project, buffer_position, cx).await;
16296
16297            if let Some((_, path)) = result {
16298                workspace
16299                    .update_in(cx, |workspace, window, cx| {
16300                        workspace.open_resolved_path(path, window, cx)
16301                    })?
16302                    .await?;
16303            }
16304            anyhow::Ok(())
16305        })
16306        .detach();
16307    }
16308
16309    pub(crate) fn navigate_to_hover_links(
16310        &mut self,
16311        kind: Option<GotoDefinitionKind>,
16312        definitions: Vec<HoverLink>,
16313        split: bool,
16314        window: &mut Window,
16315        cx: &mut Context<Editor>,
16316    ) -> Task<Result<Navigated>> {
16317        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16318        let mut first_url_or_file = None;
16319        let definitions: Vec<_> = definitions
16320            .into_iter()
16321            .filter_map(|def| match def {
16322                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16323                HoverLink::InlayHint(lsp_location, server_id) => {
16324                    let computation =
16325                        self.compute_target_location(lsp_location, server_id, window, cx);
16326                    Some(cx.background_spawn(computation))
16327                }
16328                HoverLink::Url(url) => {
16329                    first_url_or_file = Some(Either::Left(url));
16330                    None
16331                }
16332                HoverLink::File(path) => {
16333                    first_url_or_file = Some(Either::Right(path));
16334                    None
16335                }
16336            })
16337            .collect();
16338
16339        let workspace = self.workspace();
16340
16341        cx.spawn_in(window, async move |editor, acx| {
16342            let mut locations: Vec<Location> = future::join_all(definitions)
16343                .await
16344                .into_iter()
16345                .filter_map(|location| location.transpose())
16346                .collect::<Result<_>>()
16347                .context("location tasks")?;
16348
16349            if locations.len() > 1 {
16350                let Some(workspace) = workspace else {
16351                    return Ok(Navigated::No);
16352                };
16353
16354                let tab_kind = match kind {
16355                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16356                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16357                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16358                    Some(GotoDefinitionKind::Type) => "Types",
16359                };
16360                let title = editor
16361                    .update_in(acx, |_, _, cx| {
16362                        let target = locations
16363                            .iter()
16364                            .map(|location| {
16365                                location
16366                                    .buffer
16367                                    .read(cx)
16368                                    .text_for_range(location.range.clone())
16369                                    .collect::<String>()
16370                            })
16371                            .filter(|text| !text.contains('\n'))
16372                            .unique()
16373                            .take(3)
16374                            .join(", ");
16375                        if target.is_empty() {
16376                            tab_kind.to_owned()
16377                        } else {
16378                            format!("{tab_kind} for {target}")
16379                        }
16380                    })
16381                    .context("buffer title")?;
16382
16383                let opened = workspace
16384                    .update_in(acx, |workspace, window, cx| {
16385                        Self::open_locations_in_multibuffer(
16386                            workspace,
16387                            locations,
16388                            title,
16389                            split,
16390                            MultibufferSelectionMode::First,
16391                            window,
16392                            cx,
16393                        )
16394                    })
16395                    .is_ok();
16396
16397                anyhow::Ok(Navigated::from_bool(opened))
16398            } else if locations.is_empty() {
16399                // If there is one url or file, open it directly
16400                match first_url_or_file {
16401                    Some(Either::Left(url)) => {
16402                        acx.update(|_, cx| cx.open_url(&url))?;
16403                        Ok(Navigated::Yes)
16404                    }
16405                    Some(Either::Right(path)) => {
16406                        let Some(workspace) = workspace else {
16407                            return Ok(Navigated::No);
16408                        };
16409
16410                        workspace
16411                            .update_in(acx, |workspace, window, cx| {
16412                                workspace.open_resolved_path(path, window, cx)
16413                            })?
16414                            .await?;
16415                        Ok(Navigated::Yes)
16416                    }
16417                    None => Ok(Navigated::No),
16418                }
16419            } else {
16420                let Some(workspace) = workspace else {
16421                    return Ok(Navigated::No);
16422                };
16423
16424                let target = locations.pop().unwrap();
16425                editor.update_in(acx, |editor, window, cx| {
16426                    let range = target.range.to_point(target.buffer.read(cx));
16427                    let range = editor.range_for_match(&range);
16428                    let range = collapse_multiline_range(range);
16429
16430                    if !split
16431                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16432                    {
16433                        editor.go_to_singleton_buffer_range(range, window, cx);
16434                    } else {
16435                        let pane = workspace.read(cx).active_pane().clone();
16436                        window.defer(cx, move |window, cx| {
16437                            let target_editor: Entity<Self> =
16438                                workspace.update(cx, |workspace, cx| {
16439                                    let pane = if split {
16440                                        workspace.adjacent_pane(window, cx)
16441                                    } else {
16442                                        workspace.active_pane().clone()
16443                                    };
16444
16445                                    workspace.open_project_item(
16446                                        pane,
16447                                        target.buffer.clone(),
16448                                        true,
16449                                        true,
16450                                        window,
16451                                        cx,
16452                                    )
16453                                });
16454                            target_editor.update(cx, |target_editor, cx| {
16455                                // When selecting a definition in a different buffer, disable the nav history
16456                                // to avoid creating a history entry at the previous cursor location.
16457                                pane.update(cx, |pane, _| pane.disable_history());
16458                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16459                                pane.update(cx, |pane, _| pane.enable_history());
16460                            });
16461                        });
16462                    }
16463                    Navigated::Yes
16464                })
16465            }
16466        })
16467    }
16468
16469    fn compute_target_location(
16470        &self,
16471        lsp_location: lsp::Location,
16472        server_id: LanguageServerId,
16473        window: &mut Window,
16474        cx: &mut Context<Self>,
16475    ) -> Task<anyhow::Result<Option<Location>>> {
16476        let Some(project) = self.project.clone() else {
16477            return Task::ready(Ok(None));
16478        };
16479
16480        cx.spawn_in(window, async move |editor, cx| {
16481            let location_task = editor.update(cx, |_, cx| {
16482                project.update(cx, |project, cx| {
16483                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16484                })
16485            })?;
16486            let location = Some({
16487                let target_buffer_handle = location_task.await.context("open local buffer")?;
16488                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16489                    let target_start = target_buffer
16490                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16491                    let target_end = target_buffer
16492                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16493                    target_buffer.anchor_after(target_start)
16494                        ..target_buffer.anchor_before(target_end)
16495                })?;
16496                Location {
16497                    buffer: target_buffer_handle,
16498                    range,
16499                }
16500            });
16501            Ok(location)
16502        })
16503    }
16504
16505    pub fn find_all_references(
16506        &mut self,
16507        _: &FindAllReferences,
16508        window: &mut Window,
16509        cx: &mut Context<Self>,
16510    ) -> Option<Task<Result<Navigated>>> {
16511        let selection = self.selections.newest::<usize>(cx);
16512        let multi_buffer = self.buffer.read(cx);
16513        let head = selection.head();
16514
16515        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16516        let head_anchor = multi_buffer_snapshot.anchor_at(
16517            head,
16518            if head < selection.tail() {
16519                Bias::Right
16520            } else {
16521                Bias::Left
16522            },
16523        );
16524
16525        match self
16526            .find_all_references_task_sources
16527            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16528        {
16529            Ok(_) => {
16530                log::info!(
16531                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16532                );
16533                return None;
16534            }
16535            Err(i) => {
16536                self.find_all_references_task_sources.insert(i, head_anchor);
16537            }
16538        }
16539
16540        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16541        let workspace = self.workspace()?;
16542        let project = workspace.read(cx).project().clone();
16543        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16544        Some(cx.spawn_in(window, async move |editor, cx| {
16545            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16546                if let Ok(i) = editor
16547                    .find_all_references_task_sources
16548                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16549                {
16550                    editor.find_all_references_task_sources.remove(i);
16551                }
16552            });
16553
16554            let Some(locations) = references.await? else {
16555                return anyhow::Ok(Navigated::No);
16556            };
16557            if locations.is_empty() {
16558                return anyhow::Ok(Navigated::No);
16559            }
16560
16561            workspace.update_in(cx, |workspace, window, cx| {
16562                let target = locations
16563                    .iter()
16564                    .map(|location| {
16565                        location
16566                            .buffer
16567                            .read(cx)
16568                            .text_for_range(location.range.clone())
16569                            .collect::<String>()
16570                    })
16571                    .filter(|text| !text.contains('\n'))
16572                    .unique()
16573                    .take(3)
16574                    .join(", ");
16575                let title = if target.is_empty() {
16576                    "References".to_owned()
16577                } else {
16578                    format!("References to {target}")
16579                };
16580                Self::open_locations_in_multibuffer(
16581                    workspace,
16582                    locations,
16583                    title,
16584                    false,
16585                    MultibufferSelectionMode::First,
16586                    window,
16587                    cx,
16588                );
16589                Navigated::Yes
16590            })
16591        }))
16592    }
16593
16594    /// Opens a multibuffer with the given project locations in it
16595    pub fn open_locations_in_multibuffer(
16596        workspace: &mut Workspace,
16597        mut locations: Vec<Location>,
16598        title: String,
16599        split: bool,
16600        multibuffer_selection_mode: MultibufferSelectionMode,
16601        window: &mut Window,
16602        cx: &mut Context<Workspace>,
16603    ) {
16604        if locations.is_empty() {
16605            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16606            return;
16607        }
16608
16609        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16610
16611        let mut locations = locations.into_iter().peekable();
16612        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16613        let capability = workspace.project().read(cx).capability();
16614
16615        // a key to find existing multibuffer editors with the same set of locations
16616        // to prevent us from opening more and more multibuffer tabs for searches and the like
16617        let mut key = (title.clone(), vec![]);
16618        let excerpt_buffer = cx.new(|cx| {
16619            let key = &mut key.1;
16620            let mut multibuffer = MultiBuffer::new(capability);
16621            while let Some(location) = locations.next() {
16622                let buffer = location.buffer.read(cx);
16623                let mut ranges_for_buffer = Vec::new();
16624                let range = location.range.to_point(buffer);
16625                ranges_for_buffer.push(range.clone());
16626
16627                while let Some(next_location) =
16628                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16629                {
16630                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16631                }
16632
16633                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16634                key.push((
16635                    location.buffer.read(cx).remote_id(),
16636                    ranges_for_buffer.clone(),
16637                ));
16638                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16639                    PathKey::for_buffer(&location.buffer, cx),
16640                    location.buffer.clone(),
16641                    ranges_for_buffer,
16642                    multibuffer_context_lines(cx),
16643                    cx,
16644                );
16645                ranges.extend(new_ranges)
16646            }
16647
16648            multibuffer.with_title(title)
16649        });
16650        let existing = workspace.active_pane().update(cx, |pane, cx| {
16651            pane.items()
16652                .filter_map(|item| item.downcast::<Editor>())
16653                .find(|editor| {
16654                    editor
16655                        .read(cx)
16656                        .lookup_key
16657                        .as_ref()
16658                        .and_then(|it| {
16659                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16660                        })
16661                        .is_some_and(|it| *it == key)
16662                })
16663        });
16664        let editor = existing.unwrap_or_else(|| {
16665            cx.new(|cx| {
16666                let mut editor = Editor::for_multibuffer(
16667                    excerpt_buffer,
16668                    Some(workspace.project().clone()),
16669                    window,
16670                    cx,
16671                );
16672                editor.lookup_key = Some(Box::new(key));
16673                editor
16674            })
16675        });
16676        editor.update(cx, |editor, cx| {
16677            match multibuffer_selection_mode {
16678                MultibufferSelectionMode::First => {
16679                    if let Some(first_range) = ranges.first() {
16680                        editor.change_selections(
16681                            SelectionEffects::no_scroll(),
16682                            window,
16683                            cx,
16684                            |selections| {
16685                                selections.clear_disjoint();
16686                                selections
16687                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16688                            },
16689                        );
16690                    }
16691                    editor.highlight_background::<Self>(
16692                        &ranges,
16693                        |theme| theme.colors().editor_highlighted_line_background,
16694                        cx,
16695                    );
16696                }
16697                MultibufferSelectionMode::All => {
16698                    editor.change_selections(
16699                        SelectionEffects::no_scroll(),
16700                        window,
16701                        cx,
16702                        |selections| {
16703                            selections.clear_disjoint();
16704                            selections.select_anchor_ranges(ranges);
16705                        },
16706                    );
16707                }
16708            }
16709            editor.register_buffers_with_language_servers(cx);
16710        });
16711
16712        let item = Box::new(editor);
16713        let item_id = item.item_id();
16714
16715        if split {
16716            workspace.split_item(SplitDirection::Right, item, window, cx);
16717        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16718            let (preview_item_id, preview_item_idx) =
16719                workspace.active_pane().read_with(cx, |pane, _| {
16720                    (pane.preview_item_id(), pane.preview_item_idx())
16721                });
16722
16723            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16724
16725            if let Some(preview_item_id) = preview_item_id {
16726                workspace.active_pane().update(cx, |pane, cx| {
16727                    pane.remove_item(preview_item_id, false, false, window, cx);
16728                });
16729            }
16730        } else {
16731            workspace.add_item_to_active_pane(item, None, true, window, cx);
16732        }
16733        workspace.active_pane().update(cx, |pane, cx| {
16734            pane.set_preview_item_id(Some(item_id), cx);
16735        });
16736    }
16737
16738    pub fn rename(
16739        &mut self,
16740        _: &Rename,
16741        window: &mut Window,
16742        cx: &mut Context<Self>,
16743    ) -> Option<Task<Result<()>>> {
16744        use language::ToOffset as _;
16745
16746        let provider = self.semantics_provider.clone()?;
16747        let selection = self.selections.newest_anchor().clone();
16748        let (cursor_buffer, cursor_buffer_position) = self
16749            .buffer
16750            .read(cx)
16751            .text_anchor_for_position(selection.head(), cx)?;
16752        let (tail_buffer, cursor_buffer_position_end) = self
16753            .buffer
16754            .read(cx)
16755            .text_anchor_for_position(selection.tail(), cx)?;
16756        if tail_buffer != cursor_buffer {
16757            return None;
16758        }
16759
16760        let snapshot = cursor_buffer.read(cx).snapshot();
16761        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16762        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16763        let prepare_rename = provider
16764            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16765            .unwrap_or_else(|| Task::ready(Ok(None)));
16766        drop(snapshot);
16767
16768        Some(cx.spawn_in(window, async move |this, cx| {
16769            let rename_range = if let Some(range) = prepare_rename.await? {
16770                Some(range)
16771            } else {
16772                this.update(cx, |this, cx| {
16773                    let buffer = this.buffer.read(cx).snapshot(cx);
16774                    let mut buffer_highlights = this
16775                        .document_highlights_for_position(selection.head(), &buffer)
16776                        .filter(|highlight| {
16777                            highlight.start.excerpt_id == selection.head().excerpt_id
16778                                && highlight.end.excerpt_id == selection.head().excerpt_id
16779                        });
16780                    buffer_highlights
16781                        .next()
16782                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16783                })?
16784            };
16785            if let Some(rename_range) = rename_range {
16786                this.update_in(cx, |this, window, cx| {
16787                    let snapshot = cursor_buffer.read(cx).snapshot();
16788                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16789                    let cursor_offset_in_rename_range =
16790                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16791                    let cursor_offset_in_rename_range_end =
16792                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16793
16794                    this.take_rename(false, window, cx);
16795                    let buffer = this.buffer.read(cx).read(cx);
16796                    let cursor_offset = selection.head().to_offset(&buffer);
16797                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16798                    let rename_end = rename_start + rename_buffer_range.len();
16799                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16800                    let mut old_highlight_id = None;
16801                    let old_name: Arc<str> = buffer
16802                        .chunks(rename_start..rename_end, true)
16803                        .map(|chunk| {
16804                            if old_highlight_id.is_none() {
16805                                old_highlight_id = chunk.syntax_highlight_id;
16806                            }
16807                            chunk.text
16808                        })
16809                        .collect::<String>()
16810                        .into();
16811
16812                    drop(buffer);
16813
16814                    // Position the selection in the rename editor so that it matches the current selection.
16815                    this.show_local_selections = false;
16816                    let rename_editor = cx.new(|cx| {
16817                        let mut editor = Editor::single_line(window, cx);
16818                        editor.buffer.update(cx, |buffer, cx| {
16819                            buffer.edit([(0..0, old_name.clone())], None, cx)
16820                        });
16821                        let rename_selection_range = match cursor_offset_in_rename_range
16822                            .cmp(&cursor_offset_in_rename_range_end)
16823                        {
16824                            Ordering::Equal => {
16825                                editor.select_all(&SelectAll, window, cx);
16826                                return editor;
16827                            }
16828                            Ordering::Less => {
16829                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16830                            }
16831                            Ordering::Greater => {
16832                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16833                            }
16834                        };
16835                        if rename_selection_range.end > old_name.len() {
16836                            editor.select_all(&SelectAll, window, cx);
16837                        } else {
16838                            editor.change_selections(Default::default(), window, cx, |s| {
16839                                s.select_ranges([rename_selection_range]);
16840                            });
16841                        }
16842                        editor
16843                    });
16844                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16845                        if e == &EditorEvent::Focused {
16846                            cx.emit(EditorEvent::FocusedIn)
16847                        }
16848                    })
16849                    .detach();
16850
16851                    let write_highlights =
16852                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16853                    let read_highlights =
16854                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16855                    let ranges = write_highlights
16856                        .iter()
16857                        .flat_map(|(_, ranges)| ranges.iter())
16858                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16859                        .cloned()
16860                        .collect();
16861
16862                    this.highlight_text::<Rename>(
16863                        ranges,
16864                        HighlightStyle {
16865                            fade_out: Some(0.6),
16866                            ..Default::default()
16867                        },
16868                        cx,
16869                    );
16870                    let rename_focus_handle = rename_editor.focus_handle(cx);
16871                    window.focus(&rename_focus_handle);
16872                    let block_id = this.insert_blocks(
16873                        [BlockProperties {
16874                            style: BlockStyle::Flex,
16875                            placement: BlockPlacement::Below(range.start),
16876                            height: Some(1),
16877                            render: Arc::new({
16878                                let rename_editor = rename_editor.clone();
16879                                move |cx: &mut BlockContext| {
16880                                    let mut text_style = cx.editor_style.text.clone();
16881                                    if let Some(highlight_style) = old_highlight_id
16882                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16883                                    {
16884                                        text_style = text_style.highlight(highlight_style);
16885                                    }
16886                                    div()
16887                                        .block_mouse_except_scroll()
16888                                        .pl(cx.anchor_x)
16889                                        .child(EditorElement::new(
16890                                            &rename_editor,
16891                                            EditorStyle {
16892                                                background: cx.theme().system().transparent,
16893                                                local_player: cx.editor_style.local_player,
16894                                                text: text_style,
16895                                                scrollbar_width: cx.editor_style.scrollbar_width,
16896                                                syntax: cx.editor_style.syntax.clone(),
16897                                                status: cx.editor_style.status.clone(),
16898                                                inlay_hints_style: HighlightStyle {
16899                                                    font_weight: Some(FontWeight::BOLD),
16900                                                    ..make_inlay_hints_style(cx.app)
16901                                                },
16902                                                edit_prediction_styles: make_suggestion_styles(
16903                                                    cx.app,
16904                                                ),
16905                                                ..EditorStyle::default()
16906                                            },
16907                                        ))
16908                                        .into_any_element()
16909                                }
16910                            }),
16911                            priority: 0,
16912                        }],
16913                        Some(Autoscroll::fit()),
16914                        cx,
16915                    )[0];
16916                    this.pending_rename = Some(RenameState {
16917                        range,
16918                        old_name,
16919                        editor: rename_editor,
16920                        block_id,
16921                    });
16922                })?;
16923            }
16924
16925            Ok(())
16926        }))
16927    }
16928
16929    pub fn confirm_rename(
16930        &mut self,
16931        _: &ConfirmRename,
16932        window: &mut Window,
16933        cx: &mut Context<Self>,
16934    ) -> Option<Task<Result<()>>> {
16935        let rename = self.take_rename(false, window, cx)?;
16936        let workspace = self.workspace()?.downgrade();
16937        let (buffer, start) = self
16938            .buffer
16939            .read(cx)
16940            .text_anchor_for_position(rename.range.start, cx)?;
16941        let (end_buffer, _) = self
16942            .buffer
16943            .read(cx)
16944            .text_anchor_for_position(rename.range.end, cx)?;
16945        if buffer != end_buffer {
16946            return None;
16947        }
16948
16949        let old_name = rename.old_name;
16950        let new_name = rename.editor.read(cx).text(cx);
16951
16952        let rename = self.semantics_provider.as_ref()?.perform_rename(
16953            &buffer,
16954            start,
16955            new_name.clone(),
16956            cx,
16957        )?;
16958
16959        Some(cx.spawn_in(window, async move |editor, cx| {
16960            let project_transaction = rename.await?;
16961            Self::open_project_transaction(
16962                &editor,
16963                workspace,
16964                project_transaction,
16965                format!("Rename: {}{}", old_name, new_name),
16966                cx,
16967            )
16968            .await?;
16969
16970            editor.update(cx, |editor, cx| {
16971                editor.refresh_document_highlights(cx);
16972            })?;
16973            Ok(())
16974        }))
16975    }
16976
16977    fn take_rename(
16978        &mut self,
16979        moving_cursor: bool,
16980        window: &mut Window,
16981        cx: &mut Context<Self>,
16982    ) -> Option<RenameState> {
16983        let rename = self.pending_rename.take()?;
16984        if rename.editor.focus_handle(cx).is_focused(window) {
16985            window.focus(&self.focus_handle);
16986        }
16987
16988        self.remove_blocks(
16989            [rename.block_id].into_iter().collect(),
16990            Some(Autoscroll::fit()),
16991            cx,
16992        );
16993        self.clear_highlights::<Rename>(cx);
16994        self.show_local_selections = true;
16995
16996        if moving_cursor {
16997            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16998                editor.selections.newest::<usize>(cx).head()
16999            });
17000
17001            // Update the selection to match the position of the selection inside
17002            // the rename editor.
17003            let snapshot = self.buffer.read(cx).read(cx);
17004            let rename_range = rename.range.to_offset(&snapshot);
17005            let cursor_in_editor = snapshot
17006                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17007                .min(rename_range.end);
17008            drop(snapshot);
17009
17010            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17011                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17012            });
17013        } else {
17014            self.refresh_document_highlights(cx);
17015        }
17016
17017        Some(rename)
17018    }
17019
17020    pub fn pending_rename(&self) -> Option<&RenameState> {
17021        self.pending_rename.as_ref()
17022    }
17023
17024    fn format(
17025        &mut self,
17026        _: &Format,
17027        window: &mut Window,
17028        cx: &mut Context<Self>,
17029    ) -> Option<Task<Result<()>>> {
17030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17031
17032        let project = match &self.project {
17033            Some(project) => project.clone(),
17034            None => return None,
17035        };
17036
17037        Some(self.perform_format(
17038            project,
17039            FormatTrigger::Manual,
17040            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17041            window,
17042            cx,
17043        ))
17044    }
17045
17046    fn format_selections(
17047        &mut self,
17048        _: &FormatSelections,
17049        window: &mut Window,
17050        cx: &mut Context<Self>,
17051    ) -> Option<Task<Result<()>>> {
17052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17053
17054        let project = match &self.project {
17055            Some(project) => project.clone(),
17056            None => return None,
17057        };
17058
17059        let ranges = self
17060            .selections
17061            .all_adjusted(cx)
17062            .into_iter()
17063            .map(|selection| selection.range())
17064            .collect_vec();
17065
17066        Some(self.perform_format(
17067            project,
17068            FormatTrigger::Manual,
17069            FormatTarget::Ranges(ranges),
17070            window,
17071            cx,
17072        ))
17073    }
17074
17075    fn perform_format(
17076        &mut self,
17077        project: Entity<Project>,
17078        trigger: FormatTrigger,
17079        target: FormatTarget,
17080        window: &mut Window,
17081        cx: &mut Context<Self>,
17082    ) -> Task<Result<()>> {
17083        let buffer = self.buffer.clone();
17084        let (buffers, target) = match target {
17085            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17086            FormatTarget::Ranges(selection_ranges) => {
17087                let multi_buffer = buffer.read(cx);
17088                let snapshot = multi_buffer.read(cx);
17089                let mut buffers = HashSet::default();
17090                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17091                    BTreeMap::new();
17092                for selection_range in selection_ranges {
17093                    for (buffer, buffer_range, _) in
17094                        snapshot.range_to_buffer_ranges(selection_range)
17095                    {
17096                        let buffer_id = buffer.remote_id();
17097                        let start = buffer.anchor_before(buffer_range.start);
17098                        let end = buffer.anchor_after(buffer_range.end);
17099                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17100                        buffer_id_to_ranges
17101                            .entry(buffer_id)
17102                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17103                            .or_insert_with(|| vec![start..end]);
17104                    }
17105                }
17106                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17107            }
17108        };
17109
17110        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17111        let selections_prev = transaction_id_prev
17112            .and_then(|transaction_id_prev| {
17113                // default to selections as they were after the last edit, if we have them,
17114                // instead of how they are now.
17115                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17116                // will take you back to where you made the last edit, instead of staying where you scrolled
17117                self.selection_history
17118                    .transaction(transaction_id_prev)
17119                    .map(|t| t.0.clone())
17120            })
17121            .unwrap_or_else(|| self.selections.disjoint_anchors());
17122
17123        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17124        let format = project.update(cx, |project, cx| {
17125            project.format(buffers, target, true, trigger, cx)
17126        });
17127
17128        cx.spawn_in(window, async move |editor, cx| {
17129            let transaction = futures::select_biased! {
17130                transaction = format.log_err().fuse() => transaction,
17131                () = timeout => {
17132                    log::warn!("timed out waiting for formatting");
17133                    None
17134                }
17135            };
17136
17137            buffer
17138                .update(cx, |buffer, cx| {
17139                    if let Some(transaction) = transaction
17140                        && !buffer.is_singleton()
17141                    {
17142                        buffer.push_transaction(&transaction.0, cx);
17143                    }
17144                    cx.notify();
17145                })
17146                .ok();
17147
17148            if let Some(transaction_id_now) =
17149                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17150            {
17151                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17152                if has_new_transaction {
17153                    _ = editor.update(cx, |editor, _| {
17154                        editor
17155                            .selection_history
17156                            .insert_transaction(transaction_id_now, selections_prev);
17157                    });
17158                }
17159            }
17160
17161            Ok(())
17162        })
17163    }
17164
17165    fn organize_imports(
17166        &mut self,
17167        _: &OrganizeImports,
17168        window: &mut Window,
17169        cx: &mut Context<Self>,
17170    ) -> Option<Task<Result<()>>> {
17171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17172        let project = match &self.project {
17173            Some(project) => project.clone(),
17174            None => return None,
17175        };
17176        Some(self.perform_code_action_kind(
17177            project,
17178            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17179            window,
17180            cx,
17181        ))
17182    }
17183
17184    fn perform_code_action_kind(
17185        &mut self,
17186        project: Entity<Project>,
17187        kind: CodeActionKind,
17188        window: &mut Window,
17189        cx: &mut Context<Self>,
17190    ) -> Task<Result<()>> {
17191        let buffer = self.buffer.clone();
17192        let buffers = buffer.read(cx).all_buffers();
17193        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17194        let apply_action = project.update(cx, |project, cx| {
17195            project.apply_code_action_kind(buffers, kind, true, cx)
17196        });
17197        cx.spawn_in(window, async move |_, cx| {
17198            let transaction = futures::select_biased! {
17199                () = timeout => {
17200                    log::warn!("timed out waiting for executing code action");
17201                    None
17202                }
17203                transaction = apply_action.log_err().fuse() => transaction,
17204            };
17205            buffer
17206                .update(cx, |buffer, cx| {
17207                    // check if we need this
17208                    if let Some(transaction) = transaction
17209                        && !buffer.is_singleton()
17210                    {
17211                        buffer.push_transaction(&transaction.0, cx);
17212                    }
17213                    cx.notify();
17214                })
17215                .ok();
17216            Ok(())
17217        })
17218    }
17219
17220    pub fn restart_language_server(
17221        &mut self,
17222        _: &RestartLanguageServer,
17223        _: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        if let Some(project) = self.project.clone() {
17227            self.buffer.update(cx, |multi_buffer, cx| {
17228                project.update(cx, |project, cx| {
17229                    project.restart_language_servers_for_buffers(
17230                        multi_buffer.all_buffers().into_iter().collect(),
17231                        HashSet::default(),
17232                        cx,
17233                    );
17234                });
17235            })
17236        }
17237    }
17238
17239    pub fn stop_language_server(
17240        &mut self,
17241        _: &StopLanguageServer,
17242        _: &mut Window,
17243        cx: &mut Context<Self>,
17244    ) {
17245        if let Some(project) = self.project.clone() {
17246            self.buffer.update(cx, |multi_buffer, cx| {
17247                project.update(cx, |project, cx| {
17248                    project.stop_language_servers_for_buffers(
17249                        multi_buffer.all_buffers().into_iter().collect(),
17250                        HashSet::default(),
17251                        cx,
17252                    );
17253                    cx.emit(project::Event::RefreshInlayHints);
17254                });
17255            });
17256        }
17257    }
17258
17259    fn cancel_language_server_work(
17260        workspace: &mut Workspace,
17261        _: &actions::CancelLanguageServerWork,
17262        _: &mut Window,
17263        cx: &mut Context<Workspace>,
17264    ) {
17265        let project = workspace.project();
17266        let buffers = workspace
17267            .active_item(cx)
17268            .and_then(|item| item.act_as::<Editor>(cx))
17269            .map_or(HashSet::default(), |editor| {
17270                editor.read(cx).buffer.read(cx).all_buffers()
17271            });
17272        project.update(cx, |project, cx| {
17273            project.cancel_language_server_work_for_buffers(buffers, cx);
17274        });
17275    }
17276
17277    fn show_character_palette(
17278        &mut self,
17279        _: &ShowCharacterPalette,
17280        window: &mut Window,
17281        _: &mut Context<Self>,
17282    ) {
17283        window.show_character_palette();
17284    }
17285
17286    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17287        if !self.diagnostics_enabled() {
17288            return;
17289        }
17290
17291        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17292            let buffer = self.buffer.read(cx).snapshot(cx);
17293            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17294            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17295            let is_valid = buffer
17296                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17297                .any(|entry| {
17298                    entry.diagnostic.is_primary
17299                        && !entry.range.is_empty()
17300                        && entry.range.start == primary_range_start
17301                        && entry.diagnostic.message == active_diagnostics.active_message
17302                });
17303
17304            if !is_valid {
17305                self.dismiss_diagnostics(cx);
17306            }
17307        }
17308    }
17309
17310    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17311        match &self.active_diagnostics {
17312            ActiveDiagnostic::Group(group) => Some(group),
17313            _ => None,
17314        }
17315    }
17316
17317    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17318        if !self.diagnostics_enabled() {
17319            return;
17320        }
17321        self.dismiss_diagnostics(cx);
17322        self.active_diagnostics = ActiveDiagnostic::All;
17323    }
17324
17325    fn activate_diagnostics(
17326        &mut self,
17327        buffer_id: BufferId,
17328        diagnostic: DiagnosticEntry<usize>,
17329        window: &mut Window,
17330        cx: &mut Context<Self>,
17331    ) {
17332        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17333            return;
17334        }
17335        self.dismiss_diagnostics(cx);
17336        let snapshot = self.snapshot(window, cx);
17337        let buffer = self.buffer.read(cx).snapshot(cx);
17338        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17339            return;
17340        };
17341
17342        let diagnostic_group = buffer
17343            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17344            .collect::<Vec<_>>();
17345
17346        let blocks =
17347            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17348
17349        let blocks = self.display_map.update(cx, |display_map, cx| {
17350            display_map.insert_blocks(blocks, cx).into_iter().collect()
17351        });
17352        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17353            active_range: buffer.anchor_before(diagnostic.range.start)
17354                ..buffer.anchor_after(diagnostic.range.end),
17355            active_message: diagnostic.diagnostic.message.clone(),
17356            group_id: diagnostic.diagnostic.group_id,
17357            blocks,
17358        });
17359        cx.notify();
17360    }
17361
17362    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17363        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17364            return;
17365        };
17366
17367        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17368        if let ActiveDiagnostic::Group(group) = prev {
17369            self.display_map.update(cx, |display_map, cx| {
17370                display_map.remove_blocks(group.blocks, cx);
17371            });
17372            cx.notify();
17373        }
17374    }
17375
17376    /// Disable inline diagnostics rendering for this editor.
17377    pub fn disable_inline_diagnostics(&mut self) {
17378        self.inline_diagnostics_enabled = false;
17379        self.inline_diagnostics_update = Task::ready(());
17380        self.inline_diagnostics.clear();
17381    }
17382
17383    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17384        self.diagnostics_enabled = false;
17385        self.dismiss_diagnostics(cx);
17386        self.inline_diagnostics_update = Task::ready(());
17387        self.inline_diagnostics.clear();
17388    }
17389
17390    pub fn disable_word_completions(&mut self) {
17391        self.word_completions_enabled = false;
17392    }
17393
17394    pub fn diagnostics_enabled(&self) -> bool {
17395        self.diagnostics_enabled && self.mode.is_full()
17396    }
17397
17398    pub fn inline_diagnostics_enabled(&self) -> bool {
17399        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17400    }
17401
17402    pub fn show_inline_diagnostics(&self) -> bool {
17403        self.show_inline_diagnostics
17404    }
17405
17406    pub fn toggle_inline_diagnostics(
17407        &mut self,
17408        _: &ToggleInlineDiagnostics,
17409        window: &mut Window,
17410        cx: &mut Context<Editor>,
17411    ) {
17412        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17413        self.refresh_inline_diagnostics(false, window, cx);
17414    }
17415
17416    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17417        self.diagnostics_max_severity = severity;
17418        self.display_map.update(cx, |display_map, _| {
17419            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17420        });
17421    }
17422
17423    pub fn toggle_diagnostics(
17424        &mut self,
17425        _: &ToggleDiagnostics,
17426        window: &mut Window,
17427        cx: &mut Context<Editor>,
17428    ) {
17429        if !self.diagnostics_enabled() {
17430            return;
17431        }
17432
17433        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17434            EditorSettings::get_global(cx)
17435                .diagnostics_max_severity
17436                .filter(|severity| severity != &DiagnosticSeverity::Off)
17437                .unwrap_or(DiagnosticSeverity::Hint)
17438        } else {
17439            DiagnosticSeverity::Off
17440        };
17441        self.set_max_diagnostics_severity(new_severity, cx);
17442        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17443            self.active_diagnostics = ActiveDiagnostic::None;
17444            self.inline_diagnostics_update = Task::ready(());
17445            self.inline_diagnostics.clear();
17446        } else {
17447            self.refresh_inline_diagnostics(false, window, cx);
17448        }
17449
17450        cx.notify();
17451    }
17452
17453    pub fn toggle_minimap(
17454        &mut self,
17455        _: &ToggleMinimap,
17456        window: &mut Window,
17457        cx: &mut Context<Editor>,
17458    ) {
17459        if self.supports_minimap(cx) {
17460            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17461        }
17462    }
17463
17464    fn refresh_inline_diagnostics(
17465        &mut self,
17466        debounce: bool,
17467        window: &mut Window,
17468        cx: &mut Context<Self>,
17469    ) {
17470        let max_severity = ProjectSettings::get_global(cx)
17471            .diagnostics
17472            .inline
17473            .max_severity
17474            .unwrap_or(self.diagnostics_max_severity);
17475
17476        if !self.inline_diagnostics_enabled()
17477            || !self.show_inline_diagnostics
17478            || max_severity == DiagnosticSeverity::Off
17479        {
17480            self.inline_diagnostics_update = Task::ready(());
17481            self.inline_diagnostics.clear();
17482            return;
17483        }
17484
17485        let debounce_ms = ProjectSettings::get_global(cx)
17486            .diagnostics
17487            .inline
17488            .update_debounce_ms;
17489        let debounce = if debounce && debounce_ms > 0 {
17490            Some(Duration::from_millis(debounce_ms))
17491        } else {
17492            None
17493        };
17494        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17495            if let Some(debounce) = debounce {
17496                cx.background_executor().timer(debounce).await;
17497            }
17498            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17499                editor
17500                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17501                    .ok()
17502            }) else {
17503                return;
17504            };
17505
17506            let new_inline_diagnostics = cx
17507                .background_spawn(async move {
17508                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17509                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17510                        let message = diagnostic_entry
17511                            .diagnostic
17512                            .message
17513                            .split_once('\n')
17514                            .map(|(line, _)| line)
17515                            .map(SharedString::new)
17516                            .unwrap_or_else(|| {
17517                                SharedString::from(diagnostic_entry.diagnostic.message)
17518                            });
17519                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17520                        let (Ok(i) | Err(i)) = inline_diagnostics
17521                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17522                        inline_diagnostics.insert(
17523                            i,
17524                            (
17525                                start_anchor,
17526                                InlineDiagnostic {
17527                                    message,
17528                                    group_id: diagnostic_entry.diagnostic.group_id,
17529                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17530                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17531                                    severity: diagnostic_entry.diagnostic.severity,
17532                                },
17533                            ),
17534                        );
17535                    }
17536                    inline_diagnostics
17537                })
17538                .await;
17539
17540            editor
17541                .update(cx, |editor, cx| {
17542                    editor.inline_diagnostics = new_inline_diagnostics;
17543                    cx.notify();
17544                })
17545                .ok();
17546        });
17547    }
17548
17549    fn pull_diagnostics(
17550        &mut self,
17551        buffer_id: Option<BufferId>,
17552        window: &Window,
17553        cx: &mut Context<Self>,
17554    ) -> Option<()> {
17555        if !self.mode().is_full() {
17556            return None;
17557        }
17558        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17559            .diagnostics
17560            .lsp_pull_diagnostics;
17561        if !pull_diagnostics_settings.enabled {
17562            return None;
17563        }
17564        let project = self.project()?.downgrade();
17565        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17566        let mut buffers = self.buffer.read(cx).all_buffers();
17567        if let Some(buffer_id) = buffer_id {
17568            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17569        }
17570
17571        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17572            cx.background_executor().timer(debounce).await;
17573
17574            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17575                buffers
17576                    .into_iter()
17577                    .filter_map(|buffer| {
17578                        project
17579                            .update(cx, |project, cx| {
17580                                project.lsp_store().update(cx, |lsp_store, cx| {
17581                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17582                                })
17583                            })
17584                            .ok()
17585                    })
17586                    .collect::<FuturesUnordered<_>>()
17587            }) else {
17588                return;
17589            };
17590
17591            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17592                match pull_task {
17593                    Ok(()) => {
17594                        if editor
17595                            .update_in(cx, |editor, window, cx| {
17596                                editor.update_diagnostics_state(window, cx);
17597                            })
17598                            .is_err()
17599                        {
17600                            return;
17601                        }
17602                    }
17603                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17604                }
17605            }
17606        });
17607
17608        Some(())
17609    }
17610
17611    pub fn set_selections_from_remote(
17612        &mut self,
17613        selections: Vec<Selection<Anchor>>,
17614        pending_selection: Option<Selection<Anchor>>,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        let old_cursor_position = self.selections.newest_anchor().head();
17619        self.selections.change_with(cx, |s| {
17620            s.select_anchors(selections);
17621            if let Some(pending_selection) = pending_selection {
17622                s.set_pending(pending_selection, SelectMode::Character);
17623            } else {
17624                s.clear_pending();
17625            }
17626        });
17627        self.selections_did_change(
17628            false,
17629            &old_cursor_position,
17630            SelectionEffects::default(),
17631            window,
17632            cx,
17633        );
17634    }
17635
17636    pub fn transact(
17637        &mut self,
17638        window: &mut Window,
17639        cx: &mut Context<Self>,
17640        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17641    ) -> Option<TransactionId> {
17642        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17643            this.start_transaction_at(Instant::now(), window, cx);
17644            update(this, window, cx);
17645            this.end_transaction_at(Instant::now(), cx)
17646        })
17647    }
17648
17649    pub fn start_transaction_at(
17650        &mut self,
17651        now: Instant,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) -> Option<TransactionId> {
17655        self.end_selection(window, cx);
17656        if let Some(tx_id) = self
17657            .buffer
17658            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17659        {
17660            self.selection_history
17661                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17662            cx.emit(EditorEvent::TransactionBegun {
17663                transaction_id: tx_id,
17664            });
17665            Some(tx_id)
17666        } else {
17667            None
17668        }
17669    }
17670
17671    pub fn end_transaction_at(
17672        &mut self,
17673        now: Instant,
17674        cx: &mut Context<Self>,
17675    ) -> Option<TransactionId> {
17676        if let Some(transaction_id) = self
17677            .buffer
17678            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17679        {
17680            if let Some((_, end_selections)) =
17681                self.selection_history.transaction_mut(transaction_id)
17682            {
17683                *end_selections = Some(self.selections.disjoint_anchors());
17684            } else {
17685                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17686            }
17687
17688            cx.emit(EditorEvent::Edited { transaction_id });
17689            Some(transaction_id)
17690        } else {
17691            None
17692        }
17693    }
17694
17695    pub fn modify_transaction_selection_history(
17696        &mut self,
17697        transaction_id: TransactionId,
17698        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17699    ) -> bool {
17700        self.selection_history
17701            .transaction_mut(transaction_id)
17702            .map(modify)
17703            .is_some()
17704    }
17705
17706    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17707        if self.selection_mark_mode {
17708            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17709                s.move_with(|_, sel| {
17710                    sel.collapse_to(sel.head(), SelectionGoal::None);
17711                });
17712            })
17713        }
17714        self.selection_mark_mode = true;
17715        cx.notify();
17716    }
17717
17718    pub fn swap_selection_ends(
17719        &mut self,
17720        _: &actions::SwapSelectionEnds,
17721        window: &mut Window,
17722        cx: &mut Context<Self>,
17723    ) {
17724        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17725            s.move_with(|_, sel| {
17726                if sel.start != sel.end {
17727                    sel.reversed = !sel.reversed
17728                }
17729            });
17730        });
17731        self.request_autoscroll(Autoscroll::newest(), cx);
17732        cx.notify();
17733    }
17734
17735    pub fn toggle_focus(
17736        workspace: &mut Workspace,
17737        _: &actions::ToggleFocus,
17738        window: &mut Window,
17739        cx: &mut Context<Workspace>,
17740    ) {
17741        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17742            return;
17743        };
17744        workspace.activate_item(&item, true, true, window, cx);
17745    }
17746
17747    pub fn toggle_fold(
17748        &mut self,
17749        _: &actions::ToggleFold,
17750        window: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) {
17753        if self.is_singleton(cx) {
17754            let selection = self.selections.newest::<Point>(cx);
17755
17756            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17757            let range = if selection.is_empty() {
17758                let point = selection.head().to_display_point(&display_map);
17759                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17760                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17761                    .to_point(&display_map);
17762                start..end
17763            } else {
17764                selection.range()
17765            };
17766            if display_map.folds_in_range(range).next().is_some() {
17767                self.unfold_lines(&Default::default(), window, cx)
17768            } else {
17769                self.fold(&Default::default(), window, cx)
17770            }
17771        } else {
17772            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17773            let buffer_ids: HashSet<_> = self
17774                .selections
17775                .disjoint_anchor_ranges()
17776                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17777                .collect();
17778
17779            let should_unfold = buffer_ids
17780                .iter()
17781                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17782
17783            for buffer_id in buffer_ids {
17784                if should_unfold {
17785                    self.unfold_buffer(buffer_id, cx);
17786                } else {
17787                    self.fold_buffer(buffer_id, cx);
17788                }
17789            }
17790        }
17791    }
17792
17793    pub fn toggle_fold_recursive(
17794        &mut self,
17795        _: &actions::ToggleFoldRecursive,
17796        window: &mut Window,
17797        cx: &mut Context<Self>,
17798    ) {
17799        let selection = self.selections.newest::<Point>(cx);
17800
17801        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17802        let range = if selection.is_empty() {
17803            let point = selection.head().to_display_point(&display_map);
17804            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17805            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17806                .to_point(&display_map);
17807            start..end
17808        } else {
17809            selection.range()
17810        };
17811        if display_map.folds_in_range(range).next().is_some() {
17812            self.unfold_recursive(&Default::default(), window, cx)
17813        } else {
17814            self.fold_recursive(&Default::default(), window, cx)
17815        }
17816    }
17817
17818    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17819        if self.is_singleton(cx) {
17820            let mut to_fold = Vec::new();
17821            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17822            let selections = self.selections.all_adjusted(cx);
17823
17824            for selection in selections {
17825                let range = selection.range().sorted();
17826                let buffer_start_row = range.start.row;
17827
17828                if range.start.row != range.end.row {
17829                    let mut found = false;
17830                    let mut row = range.start.row;
17831                    while row <= range.end.row {
17832                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17833                        {
17834                            found = true;
17835                            row = crease.range().end.row + 1;
17836                            to_fold.push(crease);
17837                        } else {
17838                            row += 1
17839                        }
17840                    }
17841                    if found {
17842                        continue;
17843                    }
17844                }
17845
17846                for row in (0..=range.start.row).rev() {
17847                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17848                        && crease.range().end.row >= buffer_start_row
17849                    {
17850                        to_fold.push(crease);
17851                        if row <= range.start.row {
17852                            break;
17853                        }
17854                    }
17855                }
17856            }
17857
17858            self.fold_creases(to_fold, true, window, cx);
17859        } else {
17860            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17861            let buffer_ids = self
17862                .selections
17863                .disjoint_anchor_ranges()
17864                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17865                .collect::<HashSet<_>>();
17866            for buffer_id in buffer_ids {
17867                self.fold_buffer(buffer_id, cx);
17868            }
17869        }
17870    }
17871
17872    pub fn toggle_fold_all(
17873        &mut self,
17874        _: &actions::ToggleFoldAll,
17875        window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        if self.buffer.read(cx).is_singleton() {
17879            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17880            let has_folds = display_map
17881                .folds_in_range(0..display_map.buffer_snapshot.len())
17882                .next()
17883                .is_some();
17884
17885            if has_folds {
17886                self.unfold_all(&actions::UnfoldAll, window, cx);
17887            } else {
17888                self.fold_all(&actions::FoldAll, window, cx);
17889            }
17890        } else {
17891            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17892            let should_unfold = buffer_ids
17893                .iter()
17894                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17895
17896            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17897                editor
17898                    .update_in(cx, |editor, _, cx| {
17899                        for buffer_id in buffer_ids {
17900                            if should_unfold {
17901                                editor.unfold_buffer(buffer_id, cx);
17902                            } else {
17903                                editor.fold_buffer(buffer_id, cx);
17904                            }
17905                        }
17906                    })
17907                    .ok();
17908            });
17909        }
17910    }
17911
17912    fn fold_at_level(
17913        &mut self,
17914        fold_at: &FoldAtLevel,
17915        window: &mut Window,
17916        cx: &mut Context<Self>,
17917    ) {
17918        if !self.buffer.read(cx).is_singleton() {
17919            return;
17920        }
17921
17922        let fold_at_level = fold_at.0;
17923        let snapshot = self.buffer.read(cx).snapshot(cx);
17924        let mut to_fold = Vec::new();
17925        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17926
17927        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17928            while start_row < end_row {
17929                match self
17930                    .snapshot(window, cx)
17931                    .crease_for_buffer_row(MultiBufferRow(start_row))
17932                {
17933                    Some(crease) => {
17934                        let nested_start_row = crease.range().start.row + 1;
17935                        let nested_end_row = crease.range().end.row;
17936
17937                        if current_level < fold_at_level {
17938                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17939                        } else if current_level == fold_at_level {
17940                            to_fold.push(crease);
17941                        }
17942
17943                        start_row = nested_end_row + 1;
17944                    }
17945                    None => start_row += 1,
17946                }
17947            }
17948        }
17949
17950        self.fold_creases(to_fold, true, window, cx);
17951    }
17952
17953    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17954        if self.buffer.read(cx).is_singleton() {
17955            let mut fold_ranges = Vec::new();
17956            let snapshot = self.buffer.read(cx).snapshot(cx);
17957
17958            for row in 0..snapshot.max_row().0 {
17959                if let Some(foldable_range) = self
17960                    .snapshot(window, cx)
17961                    .crease_for_buffer_row(MultiBufferRow(row))
17962                {
17963                    fold_ranges.push(foldable_range);
17964                }
17965            }
17966
17967            self.fold_creases(fold_ranges, true, window, cx);
17968        } else {
17969            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17970                editor
17971                    .update_in(cx, |editor, _, cx| {
17972                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17973                            editor.fold_buffer(buffer_id, cx);
17974                        }
17975                    })
17976                    .ok();
17977            });
17978        }
17979    }
17980
17981    pub fn fold_function_bodies(
17982        &mut self,
17983        _: &actions::FoldFunctionBodies,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        let snapshot = self.buffer.read(cx).snapshot(cx);
17988
17989        let ranges = snapshot
17990            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17991            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17992            .collect::<Vec<_>>();
17993
17994        let creases = ranges
17995            .into_iter()
17996            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17997            .collect();
17998
17999        self.fold_creases(creases, true, window, cx);
18000    }
18001
18002    pub fn fold_recursive(
18003        &mut self,
18004        _: &actions::FoldRecursive,
18005        window: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        let mut to_fold = Vec::new();
18009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18010        let selections = self.selections.all_adjusted(cx);
18011
18012        for selection in selections {
18013            let range = selection.range().sorted();
18014            let buffer_start_row = range.start.row;
18015
18016            if range.start.row != range.end.row {
18017                let mut found = false;
18018                for row in range.start.row..=range.end.row {
18019                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18020                        found = true;
18021                        to_fold.push(crease);
18022                    }
18023                }
18024                if found {
18025                    continue;
18026                }
18027            }
18028
18029            for row in (0..=range.start.row).rev() {
18030                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18031                    if crease.range().end.row >= buffer_start_row {
18032                        to_fold.push(crease);
18033                    } else {
18034                        break;
18035                    }
18036                }
18037            }
18038        }
18039
18040        self.fold_creases(to_fold, true, window, cx);
18041    }
18042
18043    pub fn fold_at(
18044        &mut self,
18045        buffer_row: MultiBufferRow,
18046        window: &mut Window,
18047        cx: &mut Context<Self>,
18048    ) {
18049        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18050
18051        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18052            let autoscroll = self
18053                .selections
18054                .all::<Point>(cx)
18055                .iter()
18056                .any(|selection| crease.range().overlaps(&selection.range()));
18057
18058            self.fold_creases(vec![crease], autoscroll, window, cx);
18059        }
18060    }
18061
18062    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18063        if self.is_singleton(cx) {
18064            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18065            let buffer = &display_map.buffer_snapshot;
18066            let selections = self.selections.all::<Point>(cx);
18067            let ranges = selections
18068                .iter()
18069                .map(|s| {
18070                    let range = s.display_range(&display_map).sorted();
18071                    let mut start = range.start.to_point(&display_map);
18072                    let mut end = range.end.to_point(&display_map);
18073                    start.column = 0;
18074                    end.column = buffer.line_len(MultiBufferRow(end.row));
18075                    start..end
18076                })
18077                .collect::<Vec<_>>();
18078
18079            self.unfold_ranges(&ranges, true, true, cx);
18080        } else {
18081            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18082            let buffer_ids = self
18083                .selections
18084                .disjoint_anchor_ranges()
18085                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18086                .collect::<HashSet<_>>();
18087            for buffer_id in buffer_ids {
18088                self.unfold_buffer(buffer_id, cx);
18089            }
18090        }
18091    }
18092
18093    pub fn unfold_recursive(
18094        &mut self,
18095        _: &UnfoldRecursive,
18096        _window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) {
18099        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18100        let selections = self.selections.all::<Point>(cx);
18101        let ranges = selections
18102            .iter()
18103            .map(|s| {
18104                let mut range = s.display_range(&display_map).sorted();
18105                *range.start.column_mut() = 0;
18106                *range.end.column_mut() = display_map.line_len(range.end.row());
18107                let start = range.start.to_point(&display_map);
18108                let end = range.end.to_point(&display_map);
18109                start..end
18110            })
18111            .collect::<Vec<_>>();
18112
18113        self.unfold_ranges(&ranges, true, true, cx);
18114    }
18115
18116    pub fn unfold_at(
18117        &mut self,
18118        buffer_row: MultiBufferRow,
18119        _window: &mut Window,
18120        cx: &mut Context<Self>,
18121    ) {
18122        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18123
18124        let intersection_range = Point::new(buffer_row.0, 0)
18125            ..Point::new(
18126                buffer_row.0,
18127                display_map.buffer_snapshot.line_len(buffer_row),
18128            );
18129
18130        let autoscroll = self
18131            .selections
18132            .all::<Point>(cx)
18133            .iter()
18134            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18135
18136        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18137    }
18138
18139    pub fn unfold_all(
18140        &mut self,
18141        _: &actions::UnfoldAll,
18142        _window: &mut Window,
18143        cx: &mut Context<Self>,
18144    ) {
18145        if self.buffer.read(cx).is_singleton() {
18146            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18147            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18148        } else {
18149            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18150                editor
18151                    .update(cx, |editor, cx| {
18152                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18153                            editor.unfold_buffer(buffer_id, cx);
18154                        }
18155                    })
18156                    .ok();
18157            });
18158        }
18159    }
18160
18161    pub fn fold_selected_ranges(
18162        &mut self,
18163        _: &FoldSelectedRanges,
18164        window: &mut Window,
18165        cx: &mut Context<Self>,
18166    ) {
18167        let selections = self.selections.all_adjusted(cx);
18168        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18169        let ranges = selections
18170            .into_iter()
18171            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18172            .collect::<Vec<_>>();
18173        self.fold_creases(ranges, true, window, cx);
18174    }
18175
18176    pub fn fold_ranges<T: ToOffset + Clone>(
18177        &mut self,
18178        ranges: Vec<Range<T>>,
18179        auto_scroll: bool,
18180        window: &mut Window,
18181        cx: &mut Context<Self>,
18182    ) {
18183        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18184        let ranges = ranges
18185            .into_iter()
18186            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18187            .collect::<Vec<_>>();
18188        self.fold_creases(ranges, auto_scroll, window, cx);
18189    }
18190
18191    pub fn fold_creases<T: ToOffset + Clone>(
18192        &mut self,
18193        creases: Vec<Crease<T>>,
18194        auto_scroll: bool,
18195        _window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        if creases.is_empty() {
18199            return;
18200        }
18201
18202        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18203
18204        if auto_scroll {
18205            self.request_autoscroll(Autoscroll::fit(), cx);
18206        }
18207
18208        cx.notify();
18209
18210        self.scrollbar_marker_state.dirty = true;
18211        self.folds_did_change(cx);
18212    }
18213
18214    /// Removes any folds whose ranges intersect any of the given ranges.
18215    pub fn unfold_ranges<T: ToOffset + Clone>(
18216        &mut self,
18217        ranges: &[Range<T>],
18218        inclusive: bool,
18219        auto_scroll: bool,
18220        cx: &mut Context<Self>,
18221    ) {
18222        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18223            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18224        });
18225        self.folds_did_change(cx);
18226    }
18227
18228    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18229        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18230            return;
18231        }
18232        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18233        self.display_map.update(cx, |display_map, cx| {
18234            display_map.fold_buffers([buffer_id], cx)
18235        });
18236        cx.emit(EditorEvent::BufferFoldToggled {
18237            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18238            folded: true,
18239        });
18240        cx.notify();
18241    }
18242
18243    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18244        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18245            return;
18246        }
18247        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18248        self.display_map.update(cx, |display_map, cx| {
18249            display_map.unfold_buffers([buffer_id], cx);
18250        });
18251        cx.emit(EditorEvent::BufferFoldToggled {
18252            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18253            folded: false,
18254        });
18255        cx.notify();
18256    }
18257
18258    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18259        self.display_map.read(cx).is_buffer_folded(buffer)
18260    }
18261
18262    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18263        self.display_map.read(cx).folded_buffers()
18264    }
18265
18266    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18267        self.display_map.update(cx, |display_map, cx| {
18268            display_map.disable_header_for_buffer(buffer_id, cx);
18269        });
18270        cx.notify();
18271    }
18272
18273    /// Removes any folds with the given ranges.
18274    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18275        &mut self,
18276        ranges: &[Range<T>],
18277        type_id: TypeId,
18278        auto_scroll: bool,
18279        cx: &mut Context<Self>,
18280    ) {
18281        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18282            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18283        });
18284        self.folds_did_change(cx);
18285    }
18286
18287    fn remove_folds_with<T: ToOffset + Clone>(
18288        &mut self,
18289        ranges: &[Range<T>],
18290        auto_scroll: bool,
18291        cx: &mut Context<Self>,
18292        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18293    ) {
18294        if ranges.is_empty() {
18295            return;
18296        }
18297
18298        let mut buffers_affected = HashSet::default();
18299        let multi_buffer = self.buffer().read(cx);
18300        for range in ranges {
18301            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18302                buffers_affected.insert(buffer.read(cx).remote_id());
18303            };
18304        }
18305
18306        self.display_map.update(cx, update);
18307
18308        if auto_scroll {
18309            self.request_autoscroll(Autoscroll::fit(), cx);
18310        }
18311
18312        cx.notify();
18313        self.scrollbar_marker_state.dirty = true;
18314        self.active_indent_guides_state.dirty = true;
18315    }
18316
18317    pub fn update_renderer_widths(
18318        &mut self,
18319        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18320        cx: &mut Context<Self>,
18321    ) -> bool {
18322        self.display_map
18323            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18324    }
18325
18326    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18327        self.display_map.read(cx).fold_placeholder.clone()
18328    }
18329
18330    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18331        self.buffer.update(cx, |buffer, cx| {
18332            buffer.set_all_diff_hunks_expanded(cx);
18333        });
18334    }
18335
18336    pub fn expand_all_diff_hunks(
18337        &mut self,
18338        _: &ExpandAllDiffHunks,
18339        _window: &mut Window,
18340        cx: &mut Context<Self>,
18341    ) {
18342        self.buffer.update(cx, |buffer, cx| {
18343            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18344        });
18345    }
18346
18347    pub fn toggle_selected_diff_hunks(
18348        &mut self,
18349        _: &ToggleSelectedDiffHunks,
18350        _window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18354        self.toggle_diff_hunks_in_ranges(ranges, cx);
18355    }
18356
18357    pub fn diff_hunks_in_ranges<'a>(
18358        &'a self,
18359        ranges: &'a [Range<Anchor>],
18360        buffer: &'a MultiBufferSnapshot,
18361    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18362        ranges.iter().flat_map(move |range| {
18363            let end_excerpt_id = range.end.excerpt_id;
18364            let range = range.to_point(buffer);
18365            let mut peek_end = range.end;
18366            if range.end.row < buffer.max_row().0 {
18367                peek_end = Point::new(range.end.row + 1, 0);
18368            }
18369            buffer
18370                .diff_hunks_in_range(range.start..peek_end)
18371                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18372        })
18373    }
18374
18375    pub fn has_stageable_diff_hunks_in_ranges(
18376        &self,
18377        ranges: &[Range<Anchor>],
18378        snapshot: &MultiBufferSnapshot,
18379    ) -> bool {
18380        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18381        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18382    }
18383
18384    pub fn toggle_staged_selected_diff_hunks(
18385        &mut self,
18386        _: &::git::ToggleStaged,
18387        _: &mut Window,
18388        cx: &mut Context<Self>,
18389    ) {
18390        let snapshot = self.buffer.read(cx).snapshot(cx);
18391        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18392        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18393        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18394    }
18395
18396    pub fn set_render_diff_hunk_controls(
18397        &mut self,
18398        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18399        cx: &mut Context<Self>,
18400    ) {
18401        self.render_diff_hunk_controls = render_diff_hunk_controls;
18402        cx.notify();
18403    }
18404
18405    pub fn stage_and_next(
18406        &mut self,
18407        _: &::git::StageAndNext,
18408        window: &mut Window,
18409        cx: &mut Context<Self>,
18410    ) {
18411        self.do_stage_or_unstage_and_next(true, window, cx);
18412    }
18413
18414    pub fn unstage_and_next(
18415        &mut self,
18416        _: &::git::UnstageAndNext,
18417        window: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        self.do_stage_or_unstage_and_next(false, window, cx);
18421    }
18422
18423    pub fn stage_or_unstage_diff_hunks(
18424        &mut self,
18425        stage: bool,
18426        ranges: Vec<Range<Anchor>>,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18430        cx.spawn(async move |this, cx| {
18431            task.await?;
18432            this.update(cx, |this, cx| {
18433                let snapshot = this.buffer.read(cx).snapshot(cx);
18434                let chunk_by = this
18435                    .diff_hunks_in_ranges(&ranges, &snapshot)
18436                    .chunk_by(|hunk| hunk.buffer_id);
18437                for (buffer_id, hunks) in &chunk_by {
18438                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18439                }
18440            })
18441        })
18442        .detach_and_log_err(cx);
18443    }
18444
18445    fn save_buffers_for_ranges_if_needed(
18446        &mut self,
18447        ranges: &[Range<Anchor>],
18448        cx: &mut Context<Editor>,
18449    ) -> Task<Result<()>> {
18450        let multibuffer = self.buffer.read(cx);
18451        let snapshot = multibuffer.read(cx);
18452        let buffer_ids: HashSet<_> = ranges
18453            .iter()
18454            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18455            .collect();
18456        drop(snapshot);
18457
18458        let mut buffers = HashSet::default();
18459        for buffer_id in buffer_ids {
18460            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18461                let buffer = buffer_entity.read(cx);
18462                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18463                {
18464                    buffers.insert(buffer_entity);
18465                }
18466            }
18467        }
18468
18469        if let Some(project) = &self.project {
18470            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18471        } else {
18472            Task::ready(Ok(()))
18473        }
18474    }
18475
18476    fn do_stage_or_unstage_and_next(
18477        &mut self,
18478        stage: bool,
18479        window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18483
18484        if ranges.iter().any(|range| range.start != range.end) {
18485            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18486            return;
18487        }
18488
18489        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18490        let snapshot = self.snapshot(window, cx);
18491        let position = self.selections.newest::<Point>(cx).head();
18492        let mut row = snapshot
18493            .buffer_snapshot
18494            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18495            .find(|hunk| hunk.row_range.start.0 > position.row)
18496            .map(|hunk| hunk.row_range.start);
18497
18498        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18499        // Outside of the project diff editor, wrap around to the beginning.
18500        if !all_diff_hunks_expanded {
18501            row = row.or_else(|| {
18502                snapshot
18503                    .buffer_snapshot
18504                    .diff_hunks_in_range(Point::zero()..position)
18505                    .find(|hunk| hunk.row_range.end.0 < position.row)
18506                    .map(|hunk| hunk.row_range.start)
18507            });
18508        }
18509
18510        if let Some(row) = row {
18511            let destination = Point::new(row.0, 0);
18512            let autoscroll = Autoscroll::center();
18513
18514            self.unfold_ranges(&[destination..destination], false, false, cx);
18515            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18516                s.select_ranges([destination..destination]);
18517            });
18518        }
18519    }
18520
18521    fn do_stage_or_unstage(
18522        &self,
18523        stage: bool,
18524        buffer_id: BufferId,
18525        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18526        cx: &mut App,
18527    ) -> Option<()> {
18528        let project = self.project()?;
18529        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18530        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18531        let buffer_snapshot = buffer.read(cx).snapshot();
18532        let file_exists = buffer_snapshot
18533            .file()
18534            .is_some_and(|file| file.disk_state().exists());
18535        diff.update(cx, |diff, cx| {
18536            diff.stage_or_unstage_hunks(
18537                stage,
18538                &hunks
18539                    .map(|hunk| buffer_diff::DiffHunk {
18540                        buffer_range: hunk.buffer_range,
18541                        diff_base_byte_range: hunk.diff_base_byte_range,
18542                        secondary_status: hunk.secondary_status,
18543                        range: Point::zero()..Point::zero(), // unused
18544                    })
18545                    .collect::<Vec<_>>(),
18546                &buffer_snapshot,
18547                file_exists,
18548                cx,
18549            )
18550        });
18551        None
18552    }
18553
18554    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18555        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18556        self.buffer
18557            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18558    }
18559
18560    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18561        self.buffer.update(cx, |buffer, cx| {
18562            let ranges = vec![Anchor::min()..Anchor::max()];
18563            if !buffer.all_diff_hunks_expanded()
18564                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18565            {
18566                buffer.collapse_diff_hunks(ranges, cx);
18567                true
18568            } else {
18569                false
18570            }
18571        })
18572    }
18573
18574    fn toggle_diff_hunks_in_ranges(
18575        &mut self,
18576        ranges: Vec<Range<Anchor>>,
18577        cx: &mut Context<Editor>,
18578    ) {
18579        self.buffer.update(cx, |buffer, cx| {
18580            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18581            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18582        })
18583    }
18584
18585    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18586        self.buffer.update(cx, |buffer, cx| {
18587            let snapshot = buffer.snapshot(cx);
18588            let excerpt_id = range.end.excerpt_id;
18589            let point_range = range.to_point(&snapshot);
18590            let expand = !buffer.single_hunk_is_expanded(range, cx);
18591            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18592        })
18593    }
18594
18595    pub(crate) fn apply_all_diff_hunks(
18596        &mut self,
18597        _: &ApplyAllDiffHunks,
18598        window: &mut Window,
18599        cx: &mut Context<Self>,
18600    ) {
18601        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18602
18603        let buffers = self.buffer.read(cx).all_buffers();
18604        for branch_buffer in buffers {
18605            branch_buffer.update(cx, |branch_buffer, cx| {
18606                branch_buffer.merge_into_base(Vec::new(), cx);
18607            });
18608        }
18609
18610        if let Some(project) = self.project.clone() {
18611            self.save(
18612                SaveOptions {
18613                    format: true,
18614                    autosave: false,
18615                },
18616                project,
18617                window,
18618                cx,
18619            )
18620            .detach_and_log_err(cx);
18621        }
18622    }
18623
18624    pub(crate) fn apply_selected_diff_hunks(
18625        &mut self,
18626        _: &ApplyDiffHunk,
18627        window: &mut Window,
18628        cx: &mut Context<Self>,
18629    ) {
18630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18631        let snapshot = self.snapshot(window, cx);
18632        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18633        let mut ranges_by_buffer = HashMap::default();
18634        self.transact(window, cx, |editor, _window, cx| {
18635            for hunk in hunks {
18636                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18637                    ranges_by_buffer
18638                        .entry(buffer.clone())
18639                        .or_insert_with(Vec::new)
18640                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18641                }
18642            }
18643
18644            for (buffer, ranges) in ranges_by_buffer {
18645                buffer.update(cx, |buffer, cx| {
18646                    buffer.merge_into_base(ranges, cx);
18647                });
18648            }
18649        });
18650
18651        if let Some(project) = self.project.clone() {
18652            self.save(
18653                SaveOptions {
18654                    format: true,
18655                    autosave: false,
18656                },
18657                project,
18658                window,
18659                cx,
18660            )
18661            .detach_and_log_err(cx);
18662        }
18663    }
18664
18665    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18666        if hovered != self.gutter_hovered {
18667            self.gutter_hovered = hovered;
18668            cx.notify();
18669        }
18670    }
18671
18672    pub fn insert_blocks(
18673        &mut self,
18674        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18675        autoscroll: Option<Autoscroll>,
18676        cx: &mut Context<Self>,
18677    ) -> Vec<CustomBlockId> {
18678        let blocks = self
18679            .display_map
18680            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18681        if let Some(autoscroll) = autoscroll {
18682            self.request_autoscroll(autoscroll, cx);
18683        }
18684        cx.notify();
18685        blocks
18686    }
18687
18688    pub fn resize_blocks(
18689        &mut self,
18690        heights: HashMap<CustomBlockId, u32>,
18691        autoscroll: Option<Autoscroll>,
18692        cx: &mut Context<Self>,
18693    ) {
18694        self.display_map
18695            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18696        if let Some(autoscroll) = autoscroll {
18697            self.request_autoscroll(autoscroll, cx);
18698        }
18699        cx.notify();
18700    }
18701
18702    pub fn replace_blocks(
18703        &mut self,
18704        renderers: HashMap<CustomBlockId, RenderBlock>,
18705        autoscroll: Option<Autoscroll>,
18706        cx: &mut Context<Self>,
18707    ) {
18708        self.display_map
18709            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18710        if let Some(autoscroll) = autoscroll {
18711            self.request_autoscroll(autoscroll, cx);
18712        }
18713        cx.notify();
18714    }
18715
18716    pub fn remove_blocks(
18717        &mut self,
18718        block_ids: HashSet<CustomBlockId>,
18719        autoscroll: Option<Autoscroll>,
18720        cx: &mut Context<Self>,
18721    ) {
18722        self.display_map.update(cx, |display_map, cx| {
18723            display_map.remove_blocks(block_ids, cx)
18724        });
18725        if let Some(autoscroll) = autoscroll {
18726            self.request_autoscroll(autoscroll, cx);
18727        }
18728        cx.notify();
18729    }
18730
18731    pub fn row_for_block(
18732        &self,
18733        block_id: CustomBlockId,
18734        cx: &mut Context<Self>,
18735    ) -> Option<DisplayRow> {
18736        self.display_map
18737            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18738    }
18739
18740    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18741        self.focused_block = Some(focused_block);
18742    }
18743
18744    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18745        self.focused_block.take()
18746    }
18747
18748    pub fn insert_creases(
18749        &mut self,
18750        creases: impl IntoIterator<Item = Crease<Anchor>>,
18751        cx: &mut Context<Self>,
18752    ) -> Vec<CreaseId> {
18753        self.display_map
18754            .update(cx, |map, cx| map.insert_creases(creases, cx))
18755    }
18756
18757    pub fn remove_creases(
18758        &mut self,
18759        ids: impl IntoIterator<Item = CreaseId>,
18760        cx: &mut Context<Self>,
18761    ) -> Vec<(CreaseId, Range<Anchor>)> {
18762        self.display_map
18763            .update(cx, |map, cx| map.remove_creases(ids, cx))
18764    }
18765
18766    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18767        self.display_map
18768            .update(cx, |map, cx| map.snapshot(cx))
18769            .longest_row()
18770    }
18771
18772    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18773        self.display_map
18774            .update(cx, |map, cx| map.snapshot(cx))
18775            .max_point()
18776    }
18777
18778    pub fn text(&self, cx: &App) -> String {
18779        self.buffer.read(cx).read(cx).text()
18780    }
18781
18782    pub fn is_empty(&self, cx: &App) -> bool {
18783        self.buffer.read(cx).read(cx).is_empty()
18784    }
18785
18786    pub fn text_option(&self, cx: &App) -> Option<String> {
18787        let text = self.text(cx);
18788        let text = text.trim();
18789
18790        if text.is_empty() {
18791            return None;
18792        }
18793
18794        Some(text.to_string())
18795    }
18796
18797    pub fn set_text(
18798        &mut self,
18799        text: impl Into<Arc<str>>,
18800        window: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.transact(window, cx, |this, _, cx| {
18804            this.buffer
18805                .read(cx)
18806                .as_singleton()
18807                .expect("you can only call set_text on editors for singleton buffers")
18808                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18809        });
18810    }
18811
18812    pub fn display_text(&self, cx: &mut App) -> String {
18813        self.display_map
18814            .update(cx, |map, cx| map.snapshot(cx))
18815            .text()
18816    }
18817
18818    fn create_minimap(
18819        &self,
18820        minimap_settings: MinimapSettings,
18821        window: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) -> Option<Entity<Self>> {
18824        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18825            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18826    }
18827
18828    fn initialize_new_minimap(
18829        &self,
18830        minimap_settings: MinimapSettings,
18831        window: &mut Window,
18832        cx: &mut Context<Self>,
18833    ) -> Entity<Self> {
18834        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18835
18836        let mut minimap = Editor::new_internal(
18837            EditorMode::Minimap {
18838                parent: cx.weak_entity(),
18839            },
18840            self.buffer.clone(),
18841            None,
18842            Some(self.display_map.clone()),
18843            window,
18844            cx,
18845        );
18846        minimap.scroll_manager.clone_state(&self.scroll_manager);
18847        minimap.set_text_style_refinement(TextStyleRefinement {
18848            font_size: Some(MINIMAP_FONT_SIZE),
18849            font_weight: Some(MINIMAP_FONT_WEIGHT),
18850            ..Default::default()
18851        });
18852        minimap.update_minimap_configuration(minimap_settings, cx);
18853        cx.new(|_| minimap)
18854    }
18855
18856    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18857        let current_line_highlight = minimap_settings
18858            .current_line_highlight
18859            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18860        self.set_current_line_highlight(Some(current_line_highlight));
18861    }
18862
18863    pub fn minimap(&self) -> Option<&Entity<Self>> {
18864        self.minimap
18865            .as_ref()
18866            .filter(|_| self.minimap_visibility.visible())
18867    }
18868
18869    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18870        let mut wrap_guides = smallvec![];
18871
18872        if self.show_wrap_guides == Some(false) {
18873            return wrap_guides;
18874        }
18875
18876        let settings = self.buffer.read(cx).language_settings(cx);
18877        if settings.show_wrap_guides {
18878            match self.soft_wrap_mode(cx) {
18879                SoftWrap::Column(soft_wrap) => {
18880                    wrap_guides.push((soft_wrap as usize, true));
18881                }
18882                SoftWrap::Bounded(soft_wrap) => {
18883                    wrap_guides.push((soft_wrap as usize, true));
18884                }
18885                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18886            }
18887            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18888        }
18889
18890        wrap_guides
18891    }
18892
18893    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18894        let settings = self.buffer.read(cx).language_settings(cx);
18895        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18896        match mode {
18897            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18898                SoftWrap::None
18899            }
18900            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18901            language_settings::SoftWrap::PreferredLineLength => {
18902                SoftWrap::Column(settings.preferred_line_length)
18903            }
18904            language_settings::SoftWrap::Bounded => {
18905                SoftWrap::Bounded(settings.preferred_line_length)
18906            }
18907        }
18908    }
18909
18910    pub fn set_soft_wrap_mode(
18911        &mut self,
18912        mode: language_settings::SoftWrap,
18913
18914        cx: &mut Context<Self>,
18915    ) {
18916        self.soft_wrap_mode_override = Some(mode);
18917        cx.notify();
18918    }
18919
18920    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18921        self.hard_wrap = hard_wrap;
18922        cx.notify();
18923    }
18924
18925    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18926        self.text_style_refinement = Some(style);
18927    }
18928
18929    /// called by the Element so we know what style we were most recently rendered with.
18930    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18931        // We intentionally do not inform the display map about the minimap style
18932        // so that wrapping is not recalculated and stays consistent for the editor
18933        // and its linked minimap.
18934        if !self.mode.is_minimap() {
18935            let font = style.text.font();
18936            let font_size = style.text.font_size.to_pixels(window.rem_size());
18937            let display_map = self
18938                .placeholder_display_map
18939                .as_ref()
18940                .filter(|_| self.is_empty(cx))
18941                .unwrap_or(&self.display_map);
18942
18943            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18944        }
18945        self.style = Some(style);
18946    }
18947
18948    pub fn style(&self) -> Option<&EditorStyle> {
18949        self.style.as_ref()
18950    }
18951
18952    // Called by the element. This method is not designed to be called outside of the editor
18953    // element's layout code because it does not notify when rewrapping is computed synchronously.
18954    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18955        if self.is_empty(cx) {
18956            self.placeholder_display_map
18957                .as_ref()
18958                .map_or(false, |display_map| {
18959                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18960                })
18961        } else {
18962            self.display_map
18963                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18964        }
18965    }
18966
18967    pub fn set_soft_wrap(&mut self) {
18968        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18969    }
18970
18971    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18972        if self.soft_wrap_mode_override.is_some() {
18973            self.soft_wrap_mode_override.take();
18974        } else {
18975            let soft_wrap = match self.soft_wrap_mode(cx) {
18976                SoftWrap::GitDiff => return,
18977                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18978                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18979                    language_settings::SoftWrap::None
18980                }
18981            };
18982            self.soft_wrap_mode_override = Some(soft_wrap);
18983        }
18984        cx.notify();
18985    }
18986
18987    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18988        let Some(workspace) = self.workspace() else {
18989            return;
18990        };
18991        let fs = workspace.read(cx).app_state().fs.clone();
18992        let current_show = TabBarSettings::get_global(cx).show;
18993        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18994            setting.show = Some(!current_show);
18995        });
18996    }
18997
18998    pub fn toggle_indent_guides(
18999        &mut self,
19000        _: &ToggleIndentGuides,
19001        _: &mut Window,
19002        cx: &mut Context<Self>,
19003    ) {
19004        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19005            self.buffer
19006                .read(cx)
19007                .language_settings(cx)
19008                .indent_guides
19009                .enabled
19010        });
19011        self.show_indent_guides = Some(!currently_enabled);
19012        cx.notify();
19013    }
19014
19015    fn should_show_indent_guides(&self) -> Option<bool> {
19016        self.show_indent_guides
19017    }
19018
19019    pub fn toggle_line_numbers(
19020        &mut self,
19021        _: &ToggleLineNumbers,
19022        _: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        let mut editor_settings = EditorSettings::get_global(cx).clone();
19026        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19027        EditorSettings::override_global(editor_settings, cx);
19028    }
19029
19030    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19031        if let Some(show_line_numbers) = self.show_line_numbers {
19032            return show_line_numbers;
19033        }
19034        EditorSettings::get_global(cx).gutter.line_numbers
19035    }
19036
19037    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19038        self.use_relative_line_numbers
19039            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19040    }
19041
19042    pub fn toggle_relative_line_numbers(
19043        &mut self,
19044        _: &ToggleRelativeLineNumbers,
19045        _: &mut Window,
19046        cx: &mut Context<Self>,
19047    ) {
19048        let is_relative = self.should_use_relative_line_numbers(cx);
19049        self.set_relative_line_number(Some(!is_relative), cx)
19050    }
19051
19052    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19053        self.use_relative_line_numbers = is_relative;
19054        cx.notify();
19055    }
19056
19057    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19058        self.show_gutter = show_gutter;
19059        cx.notify();
19060    }
19061
19062    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19063        self.show_scrollbars = ScrollbarAxes {
19064            horizontal: show,
19065            vertical: show,
19066        };
19067        cx.notify();
19068    }
19069
19070    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19071        self.show_scrollbars.vertical = show;
19072        cx.notify();
19073    }
19074
19075    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19076        self.show_scrollbars.horizontal = show;
19077        cx.notify();
19078    }
19079
19080    pub fn set_minimap_visibility(
19081        &mut self,
19082        minimap_visibility: MinimapVisibility,
19083        window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        if self.minimap_visibility != minimap_visibility {
19087            if minimap_visibility.visible() && self.minimap.is_none() {
19088                let minimap_settings = EditorSettings::get_global(cx).minimap;
19089                self.minimap =
19090                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19091            }
19092            self.minimap_visibility = minimap_visibility;
19093            cx.notify();
19094        }
19095    }
19096
19097    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19098        self.set_show_scrollbars(false, cx);
19099        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19100    }
19101
19102    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19103        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19104    }
19105
19106    /// Normally the text in full mode and auto height editors is padded on the
19107    /// left side by roughly half a character width for improved hit testing.
19108    ///
19109    /// Use this method to disable this for cases where this is not wanted (e.g.
19110    /// if you want to align the editor text with some other text above or below)
19111    /// or if you want to add this padding to single-line editors.
19112    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19113        self.offset_content = offset_content;
19114        cx.notify();
19115    }
19116
19117    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19118        self.show_line_numbers = Some(show_line_numbers);
19119        cx.notify();
19120    }
19121
19122    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19123        self.disable_expand_excerpt_buttons = true;
19124        cx.notify();
19125    }
19126
19127    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19128        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19129        cx.notify();
19130    }
19131
19132    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19133        self.show_code_actions = Some(show_code_actions);
19134        cx.notify();
19135    }
19136
19137    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19138        self.show_runnables = Some(show_runnables);
19139        cx.notify();
19140    }
19141
19142    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19143        self.show_breakpoints = Some(show_breakpoints);
19144        cx.notify();
19145    }
19146
19147    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19148        if self.display_map.read(cx).masked != masked {
19149            self.display_map.update(cx, |map, _| map.masked = masked);
19150        }
19151        cx.notify()
19152    }
19153
19154    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19155        self.show_wrap_guides = Some(show_wrap_guides);
19156        cx.notify();
19157    }
19158
19159    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19160        self.show_indent_guides = Some(show_indent_guides);
19161        cx.notify();
19162    }
19163
19164    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19165        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19166            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19167                && let Some(dir) = file.abs_path(cx).parent()
19168            {
19169                return Some(dir.to_owned());
19170            }
19171
19172            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19173                return Some(project_path.path.to_path_buf());
19174            }
19175        }
19176
19177        None
19178    }
19179
19180    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19181        self.active_excerpt(cx)?
19182            .1
19183            .read(cx)
19184            .file()
19185            .and_then(|f| f.as_local())
19186    }
19187
19188    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19189        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19190            let buffer = buffer.read(cx);
19191            if let Some(project_path) = buffer.project_path(cx) {
19192                let project = self.project()?.read(cx);
19193                project.absolute_path(&project_path, cx)
19194            } else {
19195                buffer
19196                    .file()
19197                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19198            }
19199        })
19200    }
19201
19202    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19203        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19204            let project_path = buffer.read(cx).project_path(cx)?;
19205            let project = self.project()?.read(cx);
19206            let entry = project.entry_for_path(&project_path, cx)?;
19207            let path = entry.path.to_path_buf();
19208            Some(path)
19209        })
19210    }
19211
19212    pub fn reveal_in_finder(
19213        &mut self,
19214        _: &RevealInFileManager,
19215        _window: &mut Window,
19216        cx: &mut Context<Self>,
19217    ) {
19218        if let Some(target) = self.target_file(cx) {
19219            cx.reveal_path(&target.abs_path(cx));
19220        }
19221    }
19222
19223    pub fn copy_path(
19224        &mut self,
19225        _: &zed_actions::workspace::CopyPath,
19226        _window: &mut Window,
19227        cx: &mut Context<Self>,
19228    ) {
19229        if let Some(path) = self.target_file_abs_path(cx)
19230            && let Some(path) = path.to_str()
19231        {
19232            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19233        }
19234    }
19235
19236    pub fn copy_relative_path(
19237        &mut self,
19238        _: &zed_actions::workspace::CopyRelativePath,
19239        _window: &mut Window,
19240        cx: &mut Context<Self>,
19241    ) {
19242        if let Some(path) = self.target_file_path(cx)
19243            && let Some(path) = path.to_str()
19244        {
19245            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19246        }
19247    }
19248
19249    /// Returns the project path for the editor's buffer, if any buffer is
19250    /// opened in the editor.
19251    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19252        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19253            buffer.read(cx).project_path(cx)
19254        } else {
19255            None
19256        }
19257    }
19258
19259    // Returns true if the editor handled a go-to-line request
19260    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19261        maybe!({
19262            let breakpoint_store = self.breakpoint_store.as_ref()?;
19263
19264            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19265            else {
19266                self.clear_row_highlights::<ActiveDebugLine>();
19267                return None;
19268            };
19269
19270            let position = active_stack_frame.position;
19271            let buffer_id = position.buffer_id?;
19272            let snapshot = self
19273                .project
19274                .as_ref()?
19275                .read(cx)
19276                .buffer_for_id(buffer_id, cx)?
19277                .read(cx)
19278                .snapshot();
19279
19280            let mut handled = false;
19281            for (id, ExcerptRange { context, .. }) in
19282                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19283            {
19284                if context.start.cmp(&position, &snapshot).is_ge()
19285                    || context.end.cmp(&position, &snapshot).is_lt()
19286                {
19287                    continue;
19288                }
19289                let snapshot = self.buffer.read(cx).snapshot(cx);
19290                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19291
19292                handled = true;
19293                self.clear_row_highlights::<ActiveDebugLine>();
19294
19295                self.go_to_line::<ActiveDebugLine>(
19296                    multibuffer_anchor,
19297                    Some(cx.theme().colors().editor_debugger_active_line_background),
19298                    window,
19299                    cx,
19300                );
19301
19302                cx.notify();
19303            }
19304
19305            handled.then_some(())
19306        })
19307        .is_some()
19308    }
19309
19310    pub fn copy_file_name_without_extension(
19311        &mut self,
19312        _: &CopyFileNameWithoutExtension,
19313        _: &mut Window,
19314        cx: &mut Context<Self>,
19315    ) {
19316        if let Some(file) = self.target_file(cx)
19317            && let Some(file_stem) = file.path().file_stem()
19318            && let Some(name) = file_stem.to_str()
19319        {
19320            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19321        }
19322    }
19323
19324    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19325        if let Some(file) = self.target_file(cx)
19326            && let Some(file_name) = file.path().file_name()
19327            && let Some(name) = file_name.to_str()
19328        {
19329            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19330        }
19331    }
19332
19333    pub fn toggle_git_blame(
19334        &mut self,
19335        _: &::git::Blame,
19336        window: &mut Window,
19337        cx: &mut Context<Self>,
19338    ) {
19339        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19340
19341        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19342            self.start_git_blame(true, window, cx);
19343        }
19344
19345        cx.notify();
19346    }
19347
19348    pub fn toggle_git_blame_inline(
19349        &mut self,
19350        _: &ToggleGitBlameInline,
19351        window: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) {
19354        self.toggle_git_blame_inline_internal(true, window, cx);
19355        cx.notify();
19356    }
19357
19358    pub fn open_git_blame_commit(
19359        &mut self,
19360        _: &OpenGitBlameCommit,
19361        window: &mut Window,
19362        cx: &mut Context<Self>,
19363    ) {
19364        self.open_git_blame_commit_internal(window, cx);
19365    }
19366
19367    fn open_git_blame_commit_internal(
19368        &mut self,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) -> Option<()> {
19372        let blame = self.blame.as_ref()?;
19373        let snapshot = self.snapshot(window, cx);
19374        let cursor = self.selections.newest::<Point>(cx).head();
19375        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19376        let (_, blame_entry) = blame
19377            .update(cx, |blame, cx| {
19378                blame
19379                    .blame_for_rows(
19380                        &[RowInfo {
19381                            buffer_id: Some(buffer.remote_id()),
19382                            buffer_row: Some(point.row),
19383                            ..Default::default()
19384                        }],
19385                        cx,
19386                    )
19387                    .next()
19388            })
19389            .flatten()?;
19390        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19391        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19392        let workspace = self.workspace()?.downgrade();
19393        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19394        None
19395    }
19396
19397    pub fn git_blame_inline_enabled(&self) -> bool {
19398        self.git_blame_inline_enabled
19399    }
19400
19401    pub fn toggle_selection_menu(
19402        &mut self,
19403        _: &ToggleSelectionMenu,
19404        _: &mut Window,
19405        cx: &mut Context<Self>,
19406    ) {
19407        self.show_selection_menu = self
19408            .show_selection_menu
19409            .map(|show_selections_menu| !show_selections_menu)
19410            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19411
19412        cx.notify();
19413    }
19414
19415    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19416        self.show_selection_menu
19417            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19418    }
19419
19420    fn start_git_blame(
19421        &mut self,
19422        user_triggered: bool,
19423        window: &mut Window,
19424        cx: &mut Context<Self>,
19425    ) {
19426        if let Some(project) = self.project() {
19427            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19428                && buffer.read(cx).file().is_none()
19429            {
19430                return;
19431            }
19432
19433            let focused = self.focus_handle(cx).contains_focused(window, cx);
19434
19435            let project = project.clone();
19436            let blame = cx
19437                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19438            self.blame_subscription =
19439                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19440            self.blame = Some(blame);
19441        }
19442    }
19443
19444    fn toggle_git_blame_inline_internal(
19445        &mut self,
19446        user_triggered: bool,
19447        window: &mut Window,
19448        cx: &mut Context<Self>,
19449    ) {
19450        if self.git_blame_inline_enabled {
19451            self.git_blame_inline_enabled = false;
19452            self.show_git_blame_inline = false;
19453            self.show_git_blame_inline_delay_task.take();
19454        } else {
19455            self.git_blame_inline_enabled = true;
19456            self.start_git_blame_inline(user_triggered, window, cx);
19457        }
19458
19459        cx.notify();
19460    }
19461
19462    fn start_git_blame_inline(
19463        &mut self,
19464        user_triggered: bool,
19465        window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        self.start_git_blame(user_triggered, window, cx);
19469
19470        if ProjectSettings::get_global(cx)
19471            .git
19472            .inline_blame_delay()
19473            .is_some()
19474        {
19475            self.start_inline_blame_timer(window, cx);
19476        } else {
19477            self.show_git_blame_inline = true
19478        }
19479    }
19480
19481    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19482        self.blame.as_ref()
19483    }
19484
19485    pub fn show_git_blame_gutter(&self) -> bool {
19486        self.show_git_blame_gutter
19487    }
19488
19489    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19490        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19491    }
19492
19493    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19494        self.show_git_blame_inline
19495            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19496            && !self.newest_selection_head_on_empty_line(cx)
19497            && self.has_blame_entries(cx)
19498    }
19499
19500    fn has_blame_entries(&self, cx: &App) -> bool {
19501        self.blame()
19502            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19503    }
19504
19505    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19506        let cursor_anchor = self.selections.newest_anchor().head();
19507
19508        let snapshot = self.buffer.read(cx).snapshot(cx);
19509        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19510
19511        snapshot.line_len(buffer_row) == 0
19512    }
19513
19514    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19515        let buffer_and_selection = maybe!({
19516            let selection = self.selections.newest::<Point>(cx);
19517            let selection_range = selection.range();
19518
19519            let multi_buffer = self.buffer().read(cx);
19520            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19521            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19522
19523            let (buffer, range, _) = if selection.reversed {
19524                buffer_ranges.first()
19525            } else {
19526                buffer_ranges.last()
19527            }?;
19528
19529            let selection = text::ToPoint::to_point(&range.start, buffer).row
19530                ..text::ToPoint::to_point(&range.end, buffer).row;
19531            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19532        });
19533
19534        let Some((buffer, selection)) = buffer_and_selection else {
19535            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19536        };
19537
19538        let Some(project) = self.project() else {
19539            return Task::ready(Err(anyhow!("editor does not have project")));
19540        };
19541
19542        project.update(cx, |project, cx| {
19543            project.get_permalink_to_line(&buffer, selection, cx)
19544        })
19545    }
19546
19547    pub fn copy_permalink_to_line(
19548        &mut self,
19549        _: &CopyPermalinkToLine,
19550        window: &mut Window,
19551        cx: &mut Context<Self>,
19552    ) {
19553        let permalink_task = self.get_permalink_to_line(cx);
19554        let workspace = self.workspace();
19555
19556        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19557            Ok(permalink) => {
19558                cx.update(|_, cx| {
19559                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19560                })
19561                .ok();
19562            }
19563            Err(err) => {
19564                let message = format!("Failed to copy permalink: {err}");
19565
19566                anyhow::Result::<()>::Err(err).log_err();
19567
19568                if let Some(workspace) = workspace {
19569                    workspace
19570                        .update_in(cx, |workspace, _, cx| {
19571                            struct CopyPermalinkToLine;
19572
19573                            workspace.show_toast(
19574                                Toast::new(
19575                                    NotificationId::unique::<CopyPermalinkToLine>(),
19576                                    message,
19577                                ),
19578                                cx,
19579                            )
19580                        })
19581                        .ok();
19582                }
19583            }
19584        })
19585        .detach();
19586    }
19587
19588    pub fn copy_file_location(
19589        &mut self,
19590        _: &CopyFileLocation,
19591        _: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) {
19594        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19595        if let Some(file) = self.target_file(cx)
19596            && let Some(path) = file.path().to_str()
19597        {
19598            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19599        }
19600    }
19601
19602    pub fn open_permalink_to_line(
19603        &mut self,
19604        _: &OpenPermalinkToLine,
19605        window: &mut Window,
19606        cx: &mut Context<Self>,
19607    ) {
19608        let permalink_task = self.get_permalink_to_line(cx);
19609        let workspace = self.workspace();
19610
19611        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19612            Ok(permalink) => {
19613                cx.update(|_, cx| {
19614                    cx.open_url(permalink.as_ref());
19615                })
19616                .ok();
19617            }
19618            Err(err) => {
19619                let message = format!("Failed to open permalink: {err}");
19620
19621                anyhow::Result::<()>::Err(err).log_err();
19622
19623                if let Some(workspace) = workspace {
19624                    workspace
19625                        .update(cx, |workspace, cx| {
19626                            struct OpenPermalinkToLine;
19627
19628                            workspace.show_toast(
19629                                Toast::new(
19630                                    NotificationId::unique::<OpenPermalinkToLine>(),
19631                                    message,
19632                                ),
19633                                cx,
19634                            )
19635                        })
19636                        .ok();
19637                }
19638            }
19639        })
19640        .detach();
19641    }
19642
19643    pub fn insert_uuid_v4(
19644        &mut self,
19645        _: &InsertUuidV4,
19646        window: &mut Window,
19647        cx: &mut Context<Self>,
19648    ) {
19649        self.insert_uuid(UuidVersion::V4, window, cx);
19650    }
19651
19652    pub fn insert_uuid_v7(
19653        &mut self,
19654        _: &InsertUuidV7,
19655        window: &mut Window,
19656        cx: &mut Context<Self>,
19657    ) {
19658        self.insert_uuid(UuidVersion::V7, window, cx);
19659    }
19660
19661    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19663        self.transact(window, cx, |this, window, cx| {
19664            let edits = this
19665                .selections
19666                .all::<Point>(cx)
19667                .into_iter()
19668                .map(|selection| {
19669                    let uuid = match version {
19670                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19671                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19672                    };
19673
19674                    (selection.range(), uuid.to_string())
19675                });
19676            this.edit(edits, cx);
19677            this.refresh_edit_prediction(true, false, window, cx);
19678        });
19679    }
19680
19681    pub fn open_selections_in_multibuffer(
19682        &mut self,
19683        _: &OpenSelectionsInMultibuffer,
19684        window: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        let multibuffer = self.buffer.read(cx);
19688
19689        let Some(buffer) = multibuffer.as_singleton() else {
19690            return;
19691        };
19692
19693        let Some(workspace) = self.workspace() else {
19694            return;
19695        };
19696
19697        let title = multibuffer.title(cx).to_string();
19698
19699        let locations = self
19700            .selections
19701            .all_anchors(cx)
19702            .iter()
19703            .map(|selection| Location {
19704                buffer: buffer.clone(),
19705                range: selection.start.text_anchor..selection.end.text_anchor,
19706            })
19707            .collect::<Vec<_>>();
19708
19709        cx.spawn_in(window, async move |_, cx| {
19710            workspace.update_in(cx, |workspace, window, cx| {
19711                Self::open_locations_in_multibuffer(
19712                    workspace,
19713                    locations,
19714                    format!("Selections for '{title}'"),
19715                    false,
19716                    MultibufferSelectionMode::All,
19717                    window,
19718                    cx,
19719                );
19720            })
19721        })
19722        .detach();
19723    }
19724
19725    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19726    /// last highlight added will be used.
19727    ///
19728    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19729    pub fn highlight_rows<T: 'static>(
19730        &mut self,
19731        range: Range<Anchor>,
19732        color: Hsla,
19733        options: RowHighlightOptions,
19734        cx: &mut Context<Self>,
19735    ) {
19736        let snapshot = self.buffer().read(cx).snapshot(cx);
19737        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19738        let ix = row_highlights.binary_search_by(|highlight| {
19739            Ordering::Equal
19740                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19741                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19742        });
19743
19744        if let Err(mut ix) = ix {
19745            let index = post_inc(&mut self.highlight_order);
19746
19747            // If this range intersects with the preceding highlight, then merge it with
19748            // the preceding highlight. Otherwise insert a new highlight.
19749            let mut merged = false;
19750            if ix > 0 {
19751                let prev_highlight = &mut row_highlights[ix - 1];
19752                if prev_highlight
19753                    .range
19754                    .end
19755                    .cmp(&range.start, &snapshot)
19756                    .is_ge()
19757                {
19758                    ix -= 1;
19759                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19760                        prev_highlight.range.end = range.end;
19761                    }
19762                    merged = true;
19763                    prev_highlight.index = index;
19764                    prev_highlight.color = color;
19765                    prev_highlight.options = options;
19766                }
19767            }
19768
19769            if !merged {
19770                row_highlights.insert(
19771                    ix,
19772                    RowHighlight {
19773                        range,
19774                        index,
19775                        color,
19776                        options,
19777                        type_id: TypeId::of::<T>(),
19778                    },
19779                );
19780            }
19781
19782            // If any of the following highlights intersect with this one, merge them.
19783            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19784                let highlight = &row_highlights[ix];
19785                if next_highlight
19786                    .range
19787                    .start
19788                    .cmp(&highlight.range.end, &snapshot)
19789                    .is_le()
19790                {
19791                    if next_highlight
19792                        .range
19793                        .end
19794                        .cmp(&highlight.range.end, &snapshot)
19795                        .is_gt()
19796                    {
19797                        row_highlights[ix].range.end = next_highlight.range.end;
19798                    }
19799                    row_highlights.remove(ix + 1);
19800                } else {
19801                    break;
19802                }
19803            }
19804        }
19805    }
19806
19807    /// Remove any highlighted row ranges of the given type that intersect the
19808    /// given ranges.
19809    pub fn remove_highlighted_rows<T: 'static>(
19810        &mut self,
19811        ranges_to_remove: Vec<Range<Anchor>>,
19812        cx: &mut Context<Self>,
19813    ) {
19814        let snapshot = self.buffer().read(cx).snapshot(cx);
19815        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19816        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19817        row_highlights.retain(|highlight| {
19818            while let Some(range_to_remove) = ranges_to_remove.peek() {
19819                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19820                    Ordering::Less | Ordering::Equal => {
19821                        ranges_to_remove.next();
19822                    }
19823                    Ordering::Greater => {
19824                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19825                            Ordering::Less | Ordering::Equal => {
19826                                return false;
19827                            }
19828                            Ordering::Greater => break,
19829                        }
19830                    }
19831                }
19832            }
19833
19834            true
19835        })
19836    }
19837
19838    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19839    pub fn clear_row_highlights<T: 'static>(&mut self) {
19840        self.highlighted_rows.remove(&TypeId::of::<T>());
19841    }
19842
19843    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19844    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19845        self.highlighted_rows
19846            .get(&TypeId::of::<T>())
19847            .map_or(&[] as &[_], |vec| vec.as_slice())
19848            .iter()
19849            .map(|highlight| (highlight.range.clone(), highlight.color))
19850    }
19851
19852    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19853    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19854    /// Allows to ignore certain kinds of highlights.
19855    pub fn highlighted_display_rows(
19856        &self,
19857        window: &mut Window,
19858        cx: &mut App,
19859    ) -> BTreeMap<DisplayRow, LineHighlight> {
19860        let snapshot = self.snapshot(window, cx);
19861        let mut used_highlight_orders = HashMap::default();
19862        self.highlighted_rows
19863            .iter()
19864            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19865            .fold(
19866                BTreeMap::<DisplayRow, LineHighlight>::new(),
19867                |mut unique_rows, highlight| {
19868                    let start = highlight.range.start.to_display_point(&snapshot);
19869                    let end = highlight.range.end.to_display_point(&snapshot);
19870                    let start_row = start.row().0;
19871                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19872                        && end.column() == 0
19873                    {
19874                        end.row().0.saturating_sub(1)
19875                    } else {
19876                        end.row().0
19877                    };
19878                    for row in start_row..=end_row {
19879                        let used_index =
19880                            used_highlight_orders.entry(row).or_insert(highlight.index);
19881                        if highlight.index >= *used_index {
19882                            *used_index = highlight.index;
19883                            unique_rows.insert(
19884                                DisplayRow(row),
19885                                LineHighlight {
19886                                    include_gutter: highlight.options.include_gutter,
19887                                    border: None,
19888                                    background: highlight.color.into(),
19889                                    type_id: Some(highlight.type_id),
19890                                },
19891                            );
19892                        }
19893                    }
19894                    unique_rows
19895                },
19896            )
19897    }
19898
19899    pub fn highlighted_display_row_for_autoscroll(
19900        &self,
19901        snapshot: &DisplaySnapshot,
19902    ) -> Option<DisplayRow> {
19903        self.highlighted_rows
19904            .values()
19905            .flat_map(|highlighted_rows| highlighted_rows.iter())
19906            .filter_map(|highlight| {
19907                if highlight.options.autoscroll {
19908                    Some(highlight.range.start.to_display_point(snapshot).row())
19909                } else {
19910                    None
19911                }
19912            })
19913            .min()
19914    }
19915
19916    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19917        self.highlight_background::<SearchWithinRange>(
19918            ranges,
19919            |colors| colors.colors().editor_document_highlight_read_background,
19920            cx,
19921        )
19922    }
19923
19924    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19925        self.breadcrumb_header = Some(new_header);
19926    }
19927
19928    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19929        self.clear_background_highlights::<SearchWithinRange>(cx);
19930    }
19931
19932    pub fn highlight_background<T: 'static>(
19933        &mut self,
19934        ranges: &[Range<Anchor>],
19935        color_fetcher: fn(&Theme) -> Hsla,
19936        cx: &mut Context<Self>,
19937    ) {
19938        self.background_highlights.insert(
19939            HighlightKey::Type(TypeId::of::<T>()),
19940            (color_fetcher, Arc::from(ranges)),
19941        );
19942        self.scrollbar_marker_state.dirty = true;
19943        cx.notify();
19944    }
19945
19946    pub fn highlight_background_key<T: 'static>(
19947        &mut self,
19948        key: usize,
19949        ranges: &[Range<Anchor>],
19950        color_fetcher: fn(&Theme) -> Hsla,
19951        cx: &mut Context<Self>,
19952    ) {
19953        self.background_highlights.insert(
19954            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19955            (color_fetcher, Arc::from(ranges)),
19956        );
19957        self.scrollbar_marker_state.dirty = true;
19958        cx.notify();
19959    }
19960
19961    pub fn clear_background_highlights<T: 'static>(
19962        &mut self,
19963        cx: &mut Context<Self>,
19964    ) -> Option<BackgroundHighlight> {
19965        let text_highlights = self
19966            .background_highlights
19967            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19968        if !text_highlights.1.is_empty() {
19969            self.scrollbar_marker_state.dirty = true;
19970            cx.notify();
19971        }
19972        Some(text_highlights)
19973    }
19974
19975    pub fn highlight_gutter<T: 'static>(
19976        &mut self,
19977        ranges: impl Into<Vec<Range<Anchor>>>,
19978        color_fetcher: fn(&App) -> Hsla,
19979        cx: &mut Context<Self>,
19980    ) {
19981        self.gutter_highlights
19982            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19983        cx.notify();
19984    }
19985
19986    pub fn clear_gutter_highlights<T: 'static>(
19987        &mut self,
19988        cx: &mut Context<Self>,
19989    ) -> Option<GutterHighlight> {
19990        cx.notify();
19991        self.gutter_highlights.remove(&TypeId::of::<T>())
19992    }
19993
19994    pub fn insert_gutter_highlight<T: 'static>(
19995        &mut self,
19996        range: Range<Anchor>,
19997        color_fetcher: fn(&App) -> Hsla,
19998        cx: &mut Context<Self>,
19999    ) {
20000        let snapshot = self.buffer().read(cx).snapshot(cx);
20001        let mut highlights = self
20002            .gutter_highlights
20003            .remove(&TypeId::of::<T>())
20004            .map(|(_, highlights)| highlights)
20005            .unwrap_or_default();
20006        let ix = highlights.binary_search_by(|highlight| {
20007            Ordering::Equal
20008                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20009                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20010        });
20011        if let Err(ix) = ix {
20012            highlights.insert(ix, range);
20013        }
20014        self.gutter_highlights
20015            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20016    }
20017
20018    pub fn remove_gutter_highlights<T: 'static>(
20019        &mut self,
20020        ranges_to_remove: Vec<Range<Anchor>>,
20021        cx: &mut Context<Self>,
20022    ) {
20023        let snapshot = self.buffer().read(cx).snapshot(cx);
20024        let Some((color_fetcher, mut gutter_highlights)) =
20025            self.gutter_highlights.remove(&TypeId::of::<T>())
20026        else {
20027            return;
20028        };
20029        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20030        gutter_highlights.retain(|highlight| {
20031            while let Some(range_to_remove) = ranges_to_remove.peek() {
20032                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20033                    Ordering::Less | Ordering::Equal => {
20034                        ranges_to_remove.next();
20035                    }
20036                    Ordering::Greater => {
20037                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20038                            Ordering::Less | Ordering::Equal => {
20039                                return false;
20040                            }
20041                            Ordering::Greater => break,
20042                        }
20043                    }
20044                }
20045            }
20046
20047            true
20048        });
20049        self.gutter_highlights
20050            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20051    }
20052
20053    #[cfg(feature = "test-support")]
20054    pub fn all_text_highlights(
20055        &self,
20056        window: &mut Window,
20057        cx: &mut Context<Self>,
20058    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20059        let snapshot = self.snapshot(window, cx);
20060        self.display_map.update(cx, |display_map, _| {
20061            display_map
20062                .all_text_highlights()
20063                .map(|highlight| {
20064                    let (style, ranges) = highlight.as_ref();
20065                    (
20066                        *style,
20067                        ranges
20068                            .iter()
20069                            .map(|range| range.clone().to_display_points(&snapshot))
20070                            .collect(),
20071                    )
20072                })
20073                .collect()
20074        })
20075    }
20076
20077    #[cfg(feature = "test-support")]
20078    pub fn all_text_background_highlights(
20079        &self,
20080        window: &mut Window,
20081        cx: &mut Context<Self>,
20082    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20083        let snapshot = self.snapshot(window, cx);
20084        let buffer = &snapshot.buffer_snapshot;
20085        let start = buffer.anchor_before(0);
20086        let end = buffer.anchor_after(buffer.len());
20087        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20088    }
20089
20090    #[cfg(any(test, feature = "test-support"))]
20091    pub fn sorted_background_highlights_in_range(
20092        &self,
20093        search_range: Range<Anchor>,
20094        display_snapshot: &DisplaySnapshot,
20095        theme: &Theme,
20096    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20097        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20098        res.sort_by(|a, b| {
20099            a.0.start
20100                .cmp(&b.0.start)
20101                .then_with(|| a.0.end.cmp(&b.0.end))
20102                .then_with(|| a.1.cmp(&b.1))
20103        });
20104        res
20105    }
20106
20107    #[cfg(feature = "test-support")]
20108    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20109        let snapshot = self.buffer().read(cx).snapshot(cx);
20110
20111        let highlights = self
20112            .background_highlights
20113            .get(&HighlightKey::Type(TypeId::of::<
20114                items::BufferSearchHighlights,
20115            >()));
20116
20117        if let Some((_color, ranges)) = highlights {
20118            ranges
20119                .iter()
20120                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20121                .collect_vec()
20122        } else {
20123            vec![]
20124        }
20125    }
20126
20127    fn document_highlights_for_position<'a>(
20128        &'a self,
20129        position: Anchor,
20130        buffer: &'a MultiBufferSnapshot,
20131    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20132        let read_highlights = self
20133            .background_highlights
20134            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20135            .map(|h| &h.1);
20136        let write_highlights = self
20137            .background_highlights
20138            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20139            .map(|h| &h.1);
20140        let left_position = position.bias_left(buffer);
20141        let right_position = position.bias_right(buffer);
20142        read_highlights
20143            .into_iter()
20144            .chain(write_highlights)
20145            .flat_map(move |ranges| {
20146                let start_ix = match ranges.binary_search_by(|probe| {
20147                    let cmp = probe.end.cmp(&left_position, buffer);
20148                    if cmp.is_ge() {
20149                        Ordering::Greater
20150                    } else {
20151                        Ordering::Less
20152                    }
20153                }) {
20154                    Ok(i) | Err(i) => i,
20155                };
20156
20157                ranges[start_ix..]
20158                    .iter()
20159                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20160            })
20161    }
20162
20163    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20164        self.background_highlights
20165            .get(&HighlightKey::Type(TypeId::of::<T>()))
20166            .is_some_and(|(_, highlights)| !highlights.is_empty())
20167    }
20168
20169    /// Returns all background highlights for a given range.
20170    ///
20171    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20172    pub fn background_highlights_in_range(
20173        &self,
20174        search_range: Range<Anchor>,
20175        display_snapshot: &DisplaySnapshot,
20176        theme: &Theme,
20177    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20178        let mut results = Vec::new();
20179        for (color_fetcher, ranges) in self.background_highlights.values() {
20180            let color = color_fetcher(theme);
20181            let start_ix = match ranges.binary_search_by(|probe| {
20182                let cmp = probe
20183                    .end
20184                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20185                if cmp.is_gt() {
20186                    Ordering::Greater
20187                } else {
20188                    Ordering::Less
20189                }
20190            }) {
20191                Ok(i) | Err(i) => i,
20192            };
20193            for range in &ranges[start_ix..] {
20194                if range
20195                    .start
20196                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20197                    .is_ge()
20198                {
20199                    break;
20200                }
20201
20202                let start = range.start.to_display_point(display_snapshot);
20203                let end = range.end.to_display_point(display_snapshot);
20204                results.push((start..end, color))
20205            }
20206        }
20207        results
20208    }
20209
20210    pub fn gutter_highlights_in_range(
20211        &self,
20212        search_range: Range<Anchor>,
20213        display_snapshot: &DisplaySnapshot,
20214        cx: &App,
20215    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20216        let mut results = Vec::new();
20217        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20218            let color = color_fetcher(cx);
20219            let start_ix = match ranges.binary_search_by(|probe| {
20220                let cmp = probe
20221                    .end
20222                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20223                if cmp.is_gt() {
20224                    Ordering::Greater
20225                } else {
20226                    Ordering::Less
20227                }
20228            }) {
20229                Ok(i) | Err(i) => i,
20230            };
20231            for range in &ranges[start_ix..] {
20232                if range
20233                    .start
20234                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20235                    .is_ge()
20236                {
20237                    break;
20238                }
20239
20240                let start = range.start.to_display_point(display_snapshot);
20241                let end = range.end.to_display_point(display_snapshot);
20242                results.push((start..end, color))
20243            }
20244        }
20245        results
20246    }
20247
20248    /// Get the text ranges corresponding to the redaction query
20249    pub fn redacted_ranges(
20250        &self,
20251        search_range: Range<Anchor>,
20252        display_snapshot: &DisplaySnapshot,
20253        cx: &App,
20254    ) -> Vec<Range<DisplayPoint>> {
20255        display_snapshot
20256            .buffer_snapshot
20257            .redacted_ranges(search_range, |file| {
20258                if let Some(file) = file {
20259                    file.is_private()
20260                        && EditorSettings::get(
20261                            Some(SettingsLocation {
20262                                worktree_id: file.worktree_id(cx),
20263                                path: file.path().as_ref(),
20264                            }),
20265                            cx,
20266                        )
20267                        .redact_private_values
20268                } else {
20269                    false
20270                }
20271            })
20272            .map(|range| {
20273                range.start.to_display_point(display_snapshot)
20274                    ..range.end.to_display_point(display_snapshot)
20275            })
20276            .collect()
20277    }
20278
20279    pub fn highlight_text_key<T: 'static>(
20280        &mut self,
20281        key: usize,
20282        ranges: Vec<Range<Anchor>>,
20283        style: HighlightStyle,
20284        cx: &mut Context<Self>,
20285    ) {
20286        self.display_map.update(cx, |map, _| {
20287            map.highlight_text(
20288                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20289                ranges,
20290                style,
20291            );
20292        });
20293        cx.notify();
20294    }
20295
20296    pub fn highlight_text<T: 'static>(
20297        &mut self,
20298        ranges: Vec<Range<Anchor>>,
20299        style: HighlightStyle,
20300        cx: &mut Context<Self>,
20301    ) {
20302        self.display_map.update(cx, |map, _| {
20303            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20304        });
20305        cx.notify();
20306    }
20307
20308    pub(crate) fn highlight_inlays<T: 'static>(
20309        &mut self,
20310        highlights: Vec<InlayHighlight>,
20311        style: HighlightStyle,
20312        cx: &mut Context<Self>,
20313    ) {
20314        self.display_map.update(cx, |map, _| {
20315            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20316        });
20317        cx.notify();
20318    }
20319
20320    pub fn text_highlights<'a, T: 'static>(
20321        &'a self,
20322        cx: &'a App,
20323    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20324        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20325    }
20326
20327    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20328        let cleared = self
20329            .display_map
20330            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20331        if cleared {
20332            cx.notify();
20333        }
20334    }
20335
20336    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20337        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20338            && self.focus_handle.is_focused(window)
20339    }
20340
20341    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20342        self.show_cursor_when_unfocused = is_enabled;
20343        cx.notify();
20344    }
20345
20346    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20347        cx.notify();
20348    }
20349
20350    fn on_debug_session_event(
20351        &mut self,
20352        _session: Entity<Session>,
20353        event: &SessionEvent,
20354        cx: &mut Context<Self>,
20355    ) {
20356        if let SessionEvent::InvalidateInlineValue = event {
20357            self.refresh_inline_values(cx);
20358        }
20359    }
20360
20361    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20362        let Some(project) = self.project.clone() else {
20363            return;
20364        };
20365
20366        if !self.inline_value_cache.enabled {
20367            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20368            self.splice_inlays(&inlays, Vec::new(), cx);
20369            return;
20370        }
20371
20372        let current_execution_position = self
20373            .highlighted_rows
20374            .get(&TypeId::of::<ActiveDebugLine>())
20375            .and_then(|lines| lines.last().map(|line| line.range.end));
20376
20377        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20378            let inline_values = editor
20379                .update(cx, |editor, cx| {
20380                    let Some(current_execution_position) = current_execution_position else {
20381                        return Some(Task::ready(Ok(Vec::new())));
20382                    };
20383
20384                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20385                        let snapshot = buffer.snapshot(cx);
20386
20387                        let excerpt = snapshot.excerpt_containing(
20388                            current_execution_position..current_execution_position,
20389                        )?;
20390
20391                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20392                    })?;
20393
20394                    let range =
20395                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20396
20397                    project.inline_values(buffer, range, cx)
20398                })
20399                .ok()
20400                .flatten()?
20401                .await
20402                .context("refreshing debugger inlays")
20403                .log_err()?;
20404
20405            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20406
20407            for (buffer_id, inline_value) in inline_values
20408                .into_iter()
20409                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20410            {
20411                buffer_inline_values
20412                    .entry(buffer_id)
20413                    .or_default()
20414                    .push(inline_value);
20415            }
20416
20417            editor
20418                .update(cx, |editor, cx| {
20419                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20420                    let mut new_inlays = Vec::default();
20421
20422                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20423                        let buffer_id = buffer_snapshot.remote_id();
20424                        buffer_inline_values
20425                            .get(&buffer_id)
20426                            .into_iter()
20427                            .flatten()
20428                            .for_each(|hint| {
20429                                let inlay = Inlay::debugger(
20430                                    post_inc(&mut editor.next_inlay_id),
20431                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20432                                    hint.text(),
20433                                );
20434                                if !inlay.text.chars().contains(&'\n') {
20435                                    new_inlays.push(inlay);
20436                                }
20437                            });
20438                    }
20439
20440                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20441                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20442
20443                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20444                })
20445                .ok()?;
20446            Some(())
20447        });
20448    }
20449
20450    fn on_buffer_event(
20451        &mut self,
20452        multibuffer: &Entity<MultiBuffer>,
20453        event: &multi_buffer::Event,
20454        window: &mut Window,
20455        cx: &mut Context<Self>,
20456    ) {
20457        match event {
20458            multi_buffer::Event::Edited {
20459                singleton_buffer_edited,
20460                edited_buffer,
20461            } => {
20462                self.scrollbar_marker_state.dirty = true;
20463                self.active_indent_guides_state.dirty = true;
20464                self.refresh_active_diagnostics(cx);
20465                self.refresh_code_actions(window, cx);
20466                self.refresh_selected_text_highlights(true, window, cx);
20467                self.refresh_single_line_folds(window, cx);
20468                refresh_matching_bracket_highlights(self, window, cx);
20469                if self.has_active_edit_prediction() {
20470                    self.update_visible_edit_prediction(window, cx);
20471                }
20472                if let Some(project) = self.project.as_ref()
20473                    && let Some(edited_buffer) = edited_buffer
20474                {
20475                    project.update(cx, |project, cx| {
20476                        self.registered_buffers
20477                            .entry(edited_buffer.read(cx).remote_id())
20478                            .or_insert_with(|| {
20479                                project.register_buffer_with_language_servers(edited_buffer, cx)
20480                            });
20481                    });
20482                }
20483                cx.emit(EditorEvent::BufferEdited);
20484                cx.emit(SearchEvent::MatchesInvalidated);
20485
20486                if let Some(buffer) = edited_buffer {
20487                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20488                }
20489
20490                if *singleton_buffer_edited {
20491                    if let Some(buffer) = edited_buffer
20492                        && buffer.read(cx).file().is_none()
20493                    {
20494                        cx.emit(EditorEvent::TitleChanged);
20495                    }
20496                    if let Some(project) = &self.project {
20497                        #[allow(clippy::mutable_key_type)]
20498                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20499                            multibuffer
20500                                .all_buffers()
20501                                .into_iter()
20502                                .filter_map(|buffer| {
20503                                    buffer.update(cx, |buffer, cx| {
20504                                        let language = buffer.language()?;
20505                                        let should_discard = project.update(cx, |project, cx| {
20506                                            project.is_local()
20507                                                && !project.has_language_servers_for(buffer, cx)
20508                                        });
20509                                        should_discard.not().then_some(language.clone())
20510                                    })
20511                                })
20512                                .collect::<HashSet<_>>()
20513                        });
20514                        if !languages_affected.is_empty() {
20515                            self.refresh_inlay_hints(
20516                                InlayHintRefreshReason::BufferEdited(languages_affected),
20517                                cx,
20518                            );
20519                        }
20520                    }
20521                }
20522
20523                let Some(project) = &self.project else { return };
20524                let (telemetry, is_via_ssh) = {
20525                    let project = project.read(cx);
20526                    let telemetry = project.client().telemetry().clone();
20527                    let is_via_ssh = project.is_via_remote_server();
20528                    (telemetry, is_via_ssh)
20529                };
20530                refresh_linked_ranges(self, window, cx);
20531                telemetry.log_edit_event("editor", is_via_ssh);
20532            }
20533            multi_buffer::Event::ExcerptsAdded {
20534                buffer,
20535                predecessor,
20536                excerpts,
20537            } => {
20538                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20539                let buffer_id = buffer.read(cx).remote_id();
20540                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20541                    && let Some(project) = &self.project
20542                {
20543                    update_uncommitted_diff_for_buffer(
20544                        cx.entity(),
20545                        project,
20546                        [buffer.clone()],
20547                        self.buffer.clone(),
20548                        cx,
20549                    )
20550                    .detach();
20551                }
20552                self.update_lsp_data(false, Some(buffer_id), window, cx);
20553                cx.emit(EditorEvent::ExcerptsAdded {
20554                    buffer: buffer.clone(),
20555                    predecessor: *predecessor,
20556                    excerpts: excerpts.clone(),
20557                });
20558                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20559            }
20560            multi_buffer::Event::ExcerptsRemoved {
20561                ids,
20562                removed_buffer_ids,
20563            } => {
20564                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20565                let buffer = self.buffer.read(cx);
20566                self.registered_buffers
20567                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20568                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20569                cx.emit(EditorEvent::ExcerptsRemoved {
20570                    ids: ids.clone(),
20571                    removed_buffer_ids: removed_buffer_ids.clone(),
20572                });
20573            }
20574            multi_buffer::Event::ExcerptsEdited {
20575                excerpt_ids,
20576                buffer_ids,
20577            } => {
20578                self.display_map.update(cx, |map, cx| {
20579                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20580                });
20581                cx.emit(EditorEvent::ExcerptsEdited {
20582                    ids: excerpt_ids.clone(),
20583                });
20584            }
20585            multi_buffer::Event::ExcerptsExpanded { ids } => {
20586                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20587                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20588            }
20589            multi_buffer::Event::Reparsed(buffer_id) => {
20590                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20591                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20592
20593                cx.emit(EditorEvent::Reparsed(*buffer_id));
20594            }
20595            multi_buffer::Event::DiffHunksToggled => {
20596                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20597            }
20598            multi_buffer::Event::LanguageChanged(buffer_id) => {
20599                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20600                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20601                cx.emit(EditorEvent::Reparsed(*buffer_id));
20602                cx.notify();
20603            }
20604            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20605            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20606            multi_buffer::Event::FileHandleChanged
20607            | multi_buffer::Event::Reloaded
20608            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20609            multi_buffer::Event::DiagnosticsUpdated => {
20610                self.update_diagnostics_state(window, cx);
20611            }
20612            _ => {}
20613        };
20614    }
20615
20616    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20617        if !self.diagnostics_enabled() {
20618            return;
20619        }
20620        self.refresh_active_diagnostics(cx);
20621        self.refresh_inline_diagnostics(true, window, cx);
20622        self.scrollbar_marker_state.dirty = true;
20623        cx.notify();
20624    }
20625
20626    pub fn start_temporary_diff_override(&mut self) {
20627        self.load_diff_task.take();
20628        self.temporary_diff_override = true;
20629    }
20630
20631    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20632        self.temporary_diff_override = false;
20633        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20634        self.buffer.update(cx, |buffer, cx| {
20635            buffer.set_all_diff_hunks_collapsed(cx);
20636        });
20637
20638        if let Some(project) = self.project.clone() {
20639            self.load_diff_task = Some(
20640                update_uncommitted_diff_for_buffer(
20641                    cx.entity(),
20642                    &project,
20643                    self.buffer.read(cx).all_buffers(),
20644                    self.buffer.clone(),
20645                    cx,
20646                )
20647                .shared(),
20648            );
20649        }
20650    }
20651
20652    fn on_display_map_changed(
20653        &mut self,
20654        _: Entity<DisplayMap>,
20655        _: &mut Window,
20656        cx: &mut Context<Self>,
20657    ) {
20658        cx.notify();
20659    }
20660
20661    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20662        if self.diagnostics_enabled() {
20663            let new_severity = EditorSettings::get_global(cx)
20664                .diagnostics_max_severity
20665                .unwrap_or(DiagnosticSeverity::Hint);
20666            self.set_max_diagnostics_severity(new_severity, cx);
20667        }
20668        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20669        self.update_edit_prediction_settings(cx);
20670        self.refresh_edit_prediction(true, false, window, cx);
20671        self.refresh_inline_values(cx);
20672        self.refresh_inlay_hints(
20673            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20674                self.selections.newest_anchor().head(),
20675                &self.buffer.read(cx).snapshot(cx),
20676                cx,
20677            )),
20678            cx,
20679        );
20680
20681        let old_cursor_shape = self.cursor_shape;
20682        let old_show_breadcrumbs = self.show_breadcrumbs;
20683
20684        {
20685            let editor_settings = EditorSettings::get_global(cx);
20686            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20687            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20688            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20689            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20690        }
20691
20692        if old_cursor_shape != self.cursor_shape {
20693            cx.emit(EditorEvent::CursorShapeChanged);
20694        }
20695
20696        if old_show_breadcrumbs != self.show_breadcrumbs {
20697            cx.emit(EditorEvent::BreadcrumbsChanged);
20698        }
20699
20700        let project_settings = ProjectSettings::get_global(cx);
20701        self.serialize_dirty_buffers =
20702            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20703
20704        if self.mode.is_full() {
20705            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20706            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20707            if self.show_inline_diagnostics != show_inline_diagnostics {
20708                self.show_inline_diagnostics = show_inline_diagnostics;
20709                self.refresh_inline_diagnostics(false, window, cx);
20710            }
20711
20712            if self.git_blame_inline_enabled != inline_blame_enabled {
20713                self.toggle_git_blame_inline_internal(false, window, cx);
20714            }
20715
20716            let minimap_settings = EditorSettings::get_global(cx).minimap;
20717            if self.minimap_visibility != MinimapVisibility::Disabled {
20718                if self.minimap_visibility.settings_visibility()
20719                    != minimap_settings.minimap_enabled()
20720                {
20721                    self.set_minimap_visibility(
20722                        MinimapVisibility::for_mode(self.mode(), cx),
20723                        window,
20724                        cx,
20725                    );
20726                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20727                    minimap_entity.update(cx, |minimap_editor, cx| {
20728                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20729                    })
20730                }
20731            }
20732        }
20733
20734        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20735            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20736        }) {
20737            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20738                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20739            }
20740            self.refresh_colors(false, None, window, cx);
20741        }
20742
20743        cx.notify();
20744    }
20745
20746    pub fn set_searchable(&mut self, searchable: bool) {
20747        self.searchable = searchable;
20748    }
20749
20750    pub fn searchable(&self) -> bool {
20751        self.searchable
20752    }
20753
20754    fn open_proposed_changes_editor(
20755        &mut self,
20756        _: &OpenProposedChangesEditor,
20757        window: &mut Window,
20758        cx: &mut Context<Self>,
20759    ) {
20760        let Some(workspace) = self.workspace() else {
20761            cx.propagate();
20762            return;
20763        };
20764
20765        let selections = self.selections.all::<usize>(cx);
20766        let multi_buffer = self.buffer.read(cx);
20767        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20768        let mut new_selections_by_buffer = HashMap::default();
20769        for selection in selections {
20770            for (buffer, range, _) in
20771                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20772            {
20773                let mut range = range.to_point(buffer);
20774                range.start.column = 0;
20775                range.end.column = buffer.line_len(range.end.row);
20776                new_selections_by_buffer
20777                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20778                    .or_insert(Vec::new())
20779                    .push(range)
20780            }
20781        }
20782
20783        let proposed_changes_buffers = new_selections_by_buffer
20784            .into_iter()
20785            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20786            .collect::<Vec<_>>();
20787        let proposed_changes_editor = cx.new(|cx| {
20788            ProposedChangesEditor::new(
20789                "Proposed changes",
20790                proposed_changes_buffers,
20791                self.project.clone(),
20792                window,
20793                cx,
20794            )
20795        });
20796
20797        window.defer(cx, move |window, cx| {
20798            workspace.update(cx, |workspace, cx| {
20799                workspace.active_pane().update(cx, |pane, cx| {
20800                    pane.add_item(
20801                        Box::new(proposed_changes_editor),
20802                        true,
20803                        true,
20804                        None,
20805                        window,
20806                        cx,
20807                    );
20808                });
20809            });
20810        });
20811    }
20812
20813    pub fn open_excerpts_in_split(
20814        &mut self,
20815        _: &OpenExcerptsSplit,
20816        window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        self.open_excerpts_common(None, true, window, cx)
20820    }
20821
20822    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20823        self.open_excerpts_common(None, false, window, cx)
20824    }
20825
20826    fn open_excerpts_common(
20827        &mut self,
20828        jump_data: Option<JumpData>,
20829        split: bool,
20830        window: &mut Window,
20831        cx: &mut Context<Self>,
20832    ) {
20833        let Some(workspace) = self.workspace() else {
20834            cx.propagate();
20835            return;
20836        };
20837
20838        if self.buffer.read(cx).is_singleton() {
20839            cx.propagate();
20840            return;
20841        }
20842
20843        let mut new_selections_by_buffer = HashMap::default();
20844        match &jump_data {
20845            Some(JumpData::MultiBufferPoint {
20846                excerpt_id,
20847                position,
20848                anchor,
20849                line_offset_from_top,
20850            }) => {
20851                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20852                if let Some(buffer) = multi_buffer_snapshot
20853                    .buffer_id_for_excerpt(*excerpt_id)
20854                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20855                {
20856                    let buffer_snapshot = buffer.read(cx).snapshot();
20857                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20858                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20859                    } else {
20860                        buffer_snapshot.clip_point(*position, Bias::Left)
20861                    };
20862                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20863                    new_selections_by_buffer.insert(
20864                        buffer,
20865                        (
20866                            vec![jump_to_offset..jump_to_offset],
20867                            Some(*line_offset_from_top),
20868                        ),
20869                    );
20870                }
20871            }
20872            Some(JumpData::MultiBufferRow {
20873                row,
20874                line_offset_from_top,
20875            }) => {
20876                let point = MultiBufferPoint::new(row.0, 0);
20877                if let Some((buffer, buffer_point, _)) =
20878                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20879                {
20880                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20881                    new_selections_by_buffer
20882                        .entry(buffer)
20883                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20884                        .0
20885                        .push(buffer_offset..buffer_offset)
20886                }
20887            }
20888            None => {
20889                let selections = self.selections.all::<usize>(cx);
20890                let multi_buffer = self.buffer.read(cx);
20891                for selection in selections {
20892                    for (snapshot, range, _, anchor) in multi_buffer
20893                        .snapshot(cx)
20894                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20895                    {
20896                        if let Some(anchor) = anchor {
20897                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20898                            else {
20899                                continue;
20900                            };
20901                            let offset = text::ToOffset::to_offset(
20902                                &anchor.text_anchor,
20903                                &buffer_handle.read(cx).snapshot(),
20904                            );
20905                            let range = offset..offset;
20906                            new_selections_by_buffer
20907                                .entry(buffer_handle)
20908                                .or_insert((Vec::new(), None))
20909                                .0
20910                                .push(range)
20911                        } else {
20912                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20913                            else {
20914                                continue;
20915                            };
20916                            new_selections_by_buffer
20917                                .entry(buffer_handle)
20918                                .or_insert((Vec::new(), None))
20919                                .0
20920                                .push(range)
20921                        }
20922                    }
20923                }
20924            }
20925        }
20926
20927        new_selections_by_buffer
20928            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20929
20930        if new_selections_by_buffer.is_empty() {
20931            return;
20932        }
20933
20934        // We defer the pane interaction because we ourselves are a workspace item
20935        // and activating a new item causes the pane to call a method on us reentrantly,
20936        // which panics if we're on the stack.
20937        window.defer(cx, move |window, cx| {
20938            workspace.update(cx, |workspace, cx| {
20939                let pane = if split {
20940                    workspace.adjacent_pane(window, cx)
20941                } else {
20942                    workspace.active_pane().clone()
20943                };
20944
20945                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20946                    let editor = buffer
20947                        .read(cx)
20948                        .file()
20949                        .is_none()
20950                        .then(|| {
20951                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20952                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20953                            // Instead, we try to activate the existing editor in the pane first.
20954                            let (editor, pane_item_index) =
20955                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20956                                    let editor = item.downcast::<Editor>()?;
20957                                    let singleton_buffer =
20958                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20959                                    if singleton_buffer == buffer {
20960                                        Some((editor, i))
20961                                    } else {
20962                                        None
20963                                    }
20964                                })?;
20965                            pane.update(cx, |pane, cx| {
20966                                pane.activate_item(pane_item_index, true, true, window, cx)
20967                            });
20968                            Some(editor)
20969                        })
20970                        .flatten()
20971                        .unwrap_or_else(|| {
20972                            workspace.open_project_item::<Self>(
20973                                pane.clone(),
20974                                buffer,
20975                                true,
20976                                true,
20977                                window,
20978                                cx,
20979                            )
20980                        });
20981
20982                    editor.update(cx, |editor, cx| {
20983                        let autoscroll = match scroll_offset {
20984                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20985                            None => Autoscroll::newest(),
20986                        };
20987                        let nav_history = editor.nav_history.take();
20988                        editor.change_selections(
20989                            SelectionEffects::scroll(autoscroll),
20990                            window,
20991                            cx,
20992                            |s| {
20993                                s.select_ranges(ranges);
20994                            },
20995                        );
20996                        editor.nav_history = nav_history;
20997                    });
20998                }
20999            })
21000        });
21001    }
21002
21003    // For now, don't allow opening excerpts in buffers that aren't backed by
21004    // regular project files.
21005    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21006        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21007    }
21008
21009    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21010        let snapshot = self.buffer.read(cx).read(cx);
21011        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21012        Some(
21013            ranges
21014                .iter()
21015                .map(move |range| {
21016                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21017                })
21018                .collect(),
21019        )
21020    }
21021
21022    fn selection_replacement_ranges(
21023        &self,
21024        range: Range<OffsetUtf16>,
21025        cx: &mut App,
21026    ) -> Vec<Range<OffsetUtf16>> {
21027        let selections = self.selections.all::<OffsetUtf16>(cx);
21028        let newest_selection = selections
21029            .iter()
21030            .max_by_key(|selection| selection.id)
21031            .unwrap();
21032        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21033        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21034        let snapshot = self.buffer.read(cx).read(cx);
21035        selections
21036            .into_iter()
21037            .map(|mut selection| {
21038                selection.start.0 =
21039                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21040                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21041                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21042                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21043            })
21044            .collect()
21045    }
21046
21047    fn report_editor_event(
21048        &self,
21049        reported_event: ReportEditorEvent,
21050        file_extension: Option<String>,
21051        cx: &App,
21052    ) {
21053        if cfg!(any(test, feature = "test-support")) {
21054            return;
21055        }
21056
21057        let Some(project) = &self.project else { return };
21058
21059        // If None, we are in a file without an extension
21060        let file = self
21061            .buffer
21062            .read(cx)
21063            .as_singleton()
21064            .and_then(|b| b.read(cx).file());
21065        let file_extension = file_extension.or(file
21066            .as_ref()
21067            .and_then(|file| Path::new(file.file_name(cx)).extension())
21068            .and_then(|e| e.to_str())
21069            .map(|a| a.to_string()));
21070
21071        let vim_mode = vim_enabled(cx);
21072
21073        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21074        let copilot_enabled = edit_predictions_provider
21075            == language::language_settings::EditPredictionProvider::Copilot;
21076        let copilot_enabled_for_language = self
21077            .buffer
21078            .read(cx)
21079            .language_settings(cx)
21080            .show_edit_predictions;
21081
21082        let project = project.read(cx);
21083        let event_type = reported_event.event_type();
21084
21085        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21086            telemetry::event!(
21087                event_type,
21088                type = if auto_saved {"autosave"} else {"manual"},
21089                file_extension,
21090                vim_mode,
21091                copilot_enabled,
21092                copilot_enabled_for_language,
21093                edit_predictions_provider,
21094                is_via_ssh = project.is_via_remote_server(),
21095            );
21096        } else {
21097            telemetry::event!(
21098                event_type,
21099                file_extension,
21100                vim_mode,
21101                copilot_enabled,
21102                copilot_enabled_for_language,
21103                edit_predictions_provider,
21104                is_via_ssh = project.is_via_remote_server(),
21105            );
21106        };
21107    }
21108
21109    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21110    /// with each line being an array of {text, highlight} objects.
21111    fn copy_highlight_json(
21112        &mut self,
21113        _: &CopyHighlightJson,
21114        window: &mut Window,
21115        cx: &mut Context<Self>,
21116    ) {
21117        #[derive(Serialize)]
21118        struct Chunk<'a> {
21119            text: String,
21120            highlight: Option<&'a str>,
21121        }
21122
21123        let snapshot = self.buffer.read(cx).snapshot(cx);
21124        let range = self
21125            .selected_text_range(false, window, cx)
21126            .and_then(|selection| {
21127                if selection.range.is_empty() {
21128                    None
21129                } else {
21130                    Some(selection.range)
21131                }
21132            })
21133            .unwrap_or_else(|| 0..snapshot.len());
21134
21135        let chunks = snapshot.chunks(range, true);
21136        let mut lines = Vec::new();
21137        let mut line: VecDeque<Chunk> = VecDeque::new();
21138
21139        let Some(style) = self.style.as_ref() else {
21140            return;
21141        };
21142
21143        for chunk in chunks {
21144            let highlight = chunk
21145                .syntax_highlight_id
21146                .and_then(|id| id.name(&style.syntax));
21147            let mut chunk_lines = chunk.text.split('\n').peekable();
21148            while let Some(text) = chunk_lines.next() {
21149                let mut merged_with_last_token = false;
21150                if let Some(last_token) = line.back_mut()
21151                    && last_token.highlight == highlight
21152                {
21153                    last_token.text.push_str(text);
21154                    merged_with_last_token = true;
21155                }
21156
21157                if !merged_with_last_token {
21158                    line.push_back(Chunk {
21159                        text: text.into(),
21160                        highlight,
21161                    });
21162                }
21163
21164                if chunk_lines.peek().is_some() {
21165                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21166                        line.pop_front();
21167                    }
21168                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21169                        line.pop_back();
21170                    }
21171
21172                    lines.push(mem::take(&mut line));
21173                }
21174            }
21175        }
21176
21177        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21178            return;
21179        };
21180        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21181    }
21182
21183    pub fn open_context_menu(
21184        &mut self,
21185        _: &OpenContextMenu,
21186        window: &mut Window,
21187        cx: &mut Context<Self>,
21188    ) {
21189        self.request_autoscroll(Autoscroll::newest(), cx);
21190        let position = self.selections.newest_display(cx).start;
21191        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21192    }
21193
21194    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21195        &self.inlay_hint_cache
21196    }
21197
21198    pub fn replay_insert_event(
21199        &mut self,
21200        text: &str,
21201        relative_utf16_range: Option<Range<isize>>,
21202        window: &mut Window,
21203        cx: &mut Context<Self>,
21204    ) {
21205        if !self.input_enabled {
21206            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21207            return;
21208        }
21209        if let Some(relative_utf16_range) = relative_utf16_range {
21210            let selections = self.selections.all::<OffsetUtf16>(cx);
21211            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21212                let new_ranges = selections.into_iter().map(|range| {
21213                    let start = OffsetUtf16(
21214                        range
21215                            .head()
21216                            .0
21217                            .saturating_add_signed(relative_utf16_range.start),
21218                    );
21219                    let end = OffsetUtf16(
21220                        range
21221                            .head()
21222                            .0
21223                            .saturating_add_signed(relative_utf16_range.end),
21224                    );
21225                    start..end
21226                });
21227                s.select_ranges(new_ranges);
21228            });
21229        }
21230
21231        self.handle_input(text, window, cx);
21232    }
21233
21234    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21235        let Some(provider) = self.semantics_provider.as_ref() else {
21236            return false;
21237        };
21238
21239        let mut supports = false;
21240        self.buffer().update(cx, |this, cx| {
21241            this.for_each_buffer(|buffer| {
21242                supports |= provider.supports_inlay_hints(buffer, cx);
21243            });
21244        });
21245
21246        supports
21247    }
21248
21249    pub fn is_focused(&self, window: &Window) -> bool {
21250        self.focus_handle.is_focused(window)
21251    }
21252
21253    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21254        cx.emit(EditorEvent::Focused);
21255
21256        if let Some(descendant) = self
21257            .last_focused_descendant
21258            .take()
21259            .and_then(|descendant| descendant.upgrade())
21260        {
21261            window.focus(&descendant);
21262        } else {
21263            if let Some(blame) = self.blame.as_ref() {
21264                blame.update(cx, GitBlame::focus)
21265            }
21266
21267            self.blink_manager.update(cx, BlinkManager::enable);
21268            self.show_cursor_names(window, cx);
21269            self.buffer.update(cx, |buffer, cx| {
21270                buffer.finalize_last_transaction(cx);
21271                if self.leader_id.is_none() {
21272                    buffer.set_active_selections(
21273                        &self.selections.disjoint_anchors(),
21274                        self.selections.line_mode,
21275                        self.cursor_shape,
21276                        cx,
21277                    );
21278                }
21279            });
21280        }
21281    }
21282
21283    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21284        cx.emit(EditorEvent::FocusedIn)
21285    }
21286
21287    fn handle_focus_out(
21288        &mut self,
21289        event: FocusOutEvent,
21290        _window: &mut Window,
21291        cx: &mut Context<Self>,
21292    ) {
21293        if event.blurred != self.focus_handle {
21294            self.last_focused_descendant = Some(event.blurred);
21295        }
21296        self.selection_drag_state = SelectionDragState::None;
21297        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21298    }
21299
21300    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21301        self.blink_manager.update(cx, BlinkManager::disable);
21302        self.buffer
21303            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21304
21305        if let Some(blame) = self.blame.as_ref() {
21306            blame.update(cx, GitBlame::blur)
21307        }
21308        if !self.hover_state.focused(window, cx) {
21309            hide_hover(self, cx);
21310        }
21311        if !self
21312            .context_menu
21313            .borrow()
21314            .as_ref()
21315            .is_some_and(|context_menu| context_menu.focused(window, cx))
21316        {
21317            self.hide_context_menu(window, cx);
21318        }
21319        self.discard_edit_prediction(false, cx);
21320        cx.emit(EditorEvent::Blurred);
21321        cx.notify();
21322    }
21323
21324    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21325        let mut pending: String = window
21326            .pending_input_keystrokes()
21327            .into_iter()
21328            .flatten()
21329            .filter_map(|keystroke| {
21330                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21331                    keystroke.key_char.clone()
21332                } else {
21333                    None
21334                }
21335            })
21336            .collect();
21337
21338        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21339            pending = "".to_string();
21340        }
21341
21342        let existing_pending = self
21343            .text_highlights::<PendingInput>(cx)
21344            .map(|(_, ranges)| ranges.to_vec());
21345        if existing_pending.is_none() && pending.is_empty() {
21346            return;
21347        }
21348        let transaction =
21349            self.transact(window, cx, |this, window, cx| {
21350                let selections = this.selections.all::<usize>(cx);
21351                let edits = selections
21352                    .iter()
21353                    .map(|selection| (selection.end..selection.end, pending.clone()));
21354                this.edit(edits, cx);
21355                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21356                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21357                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21358                    }));
21359                });
21360                if let Some(existing_ranges) = existing_pending {
21361                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21362                    this.edit(edits, cx);
21363                }
21364            });
21365
21366        let snapshot = self.snapshot(window, cx);
21367        let ranges = self
21368            .selections
21369            .all::<usize>(cx)
21370            .into_iter()
21371            .map(|selection| {
21372                snapshot.buffer_snapshot.anchor_after(selection.end)
21373                    ..snapshot
21374                        .buffer_snapshot
21375                        .anchor_before(selection.end + pending.len())
21376            })
21377            .collect();
21378
21379        if pending.is_empty() {
21380            self.clear_highlights::<PendingInput>(cx);
21381        } else {
21382            self.highlight_text::<PendingInput>(
21383                ranges,
21384                HighlightStyle {
21385                    underline: Some(UnderlineStyle {
21386                        thickness: px(1.),
21387                        color: None,
21388                        wavy: false,
21389                    }),
21390                    ..Default::default()
21391                },
21392                cx,
21393            );
21394        }
21395
21396        self.ime_transaction = self.ime_transaction.or(transaction);
21397        if let Some(transaction) = self.ime_transaction {
21398            self.buffer.update(cx, |buffer, cx| {
21399                buffer.group_until_transaction(transaction, cx);
21400            });
21401        }
21402
21403        if self.text_highlights::<PendingInput>(cx).is_none() {
21404            self.ime_transaction.take();
21405        }
21406    }
21407
21408    pub fn register_action_renderer(
21409        &mut self,
21410        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21411    ) -> Subscription {
21412        let id = self.next_editor_action_id.post_inc();
21413        self.editor_actions
21414            .borrow_mut()
21415            .insert(id, Box::new(listener));
21416
21417        let editor_actions = self.editor_actions.clone();
21418        Subscription::new(move || {
21419            editor_actions.borrow_mut().remove(&id);
21420        })
21421    }
21422
21423    pub fn register_action<A: Action>(
21424        &mut self,
21425        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21426    ) -> Subscription {
21427        let id = self.next_editor_action_id.post_inc();
21428        let listener = Arc::new(listener);
21429        self.editor_actions.borrow_mut().insert(
21430            id,
21431            Box::new(move |_, window, _| {
21432                let listener = listener.clone();
21433                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21434                    let action = action.downcast_ref().unwrap();
21435                    if phase == DispatchPhase::Bubble {
21436                        listener(action, window, cx)
21437                    }
21438                })
21439            }),
21440        );
21441
21442        let editor_actions = self.editor_actions.clone();
21443        Subscription::new(move || {
21444            editor_actions.borrow_mut().remove(&id);
21445        })
21446    }
21447
21448    pub fn file_header_size(&self) -> u32 {
21449        FILE_HEADER_HEIGHT
21450    }
21451
21452    pub fn restore(
21453        &mut self,
21454        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21455        window: &mut Window,
21456        cx: &mut Context<Self>,
21457    ) {
21458        let workspace = self.workspace();
21459        let project = self.project();
21460        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21461            let mut tasks = Vec::new();
21462            for (buffer_id, changes) in revert_changes {
21463                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21464                    buffer.update(cx, |buffer, cx| {
21465                        buffer.edit(
21466                            changes
21467                                .into_iter()
21468                                .map(|(range, text)| (range, text.to_string())),
21469                            None,
21470                            cx,
21471                        );
21472                    });
21473
21474                    if let Some(project) =
21475                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21476                    {
21477                        project.update(cx, |project, cx| {
21478                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21479                        })
21480                    }
21481                }
21482            }
21483            tasks
21484        });
21485        cx.spawn_in(window, async move |_, cx| {
21486            for (buffer, task) in save_tasks {
21487                let result = task.await;
21488                if result.is_err() {
21489                    let Some(path) = buffer
21490                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21491                        .ok()
21492                    else {
21493                        continue;
21494                    };
21495                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21496                        let Some(task) = cx
21497                            .update_window_entity(workspace, |workspace, window, cx| {
21498                                workspace
21499                                    .open_path_preview(path, None, false, false, false, window, cx)
21500                            })
21501                            .ok()
21502                        else {
21503                            continue;
21504                        };
21505                        task.await.log_err();
21506                    }
21507                }
21508            }
21509        })
21510        .detach();
21511        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21512            selections.refresh()
21513        });
21514    }
21515
21516    pub fn to_pixel_point(
21517        &self,
21518        source: multi_buffer::Anchor,
21519        editor_snapshot: &EditorSnapshot,
21520        window: &mut Window,
21521    ) -> Option<gpui::Point<Pixels>> {
21522        let source_point = source.to_display_point(editor_snapshot);
21523        self.display_to_pixel_point(source_point, editor_snapshot, window)
21524    }
21525
21526    pub fn display_to_pixel_point(
21527        &self,
21528        source: DisplayPoint,
21529        editor_snapshot: &EditorSnapshot,
21530        window: &mut Window,
21531    ) -> Option<gpui::Point<Pixels>> {
21532        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21533        let text_layout_details = self.text_layout_details(window);
21534        let scroll_top = text_layout_details
21535            .scroll_anchor
21536            .scroll_position(editor_snapshot)
21537            .y;
21538
21539        if source.row().as_f32() < scroll_top.floor() {
21540            return None;
21541        }
21542        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21543        let source_y = line_height * (source.row().as_f32() - scroll_top);
21544        Some(gpui::Point::new(source_x, source_y))
21545    }
21546
21547    pub fn has_visible_completions_menu(&self) -> bool {
21548        !self.edit_prediction_preview_is_active()
21549            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21550                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21551            })
21552    }
21553
21554    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21555        if self.mode.is_minimap() {
21556            return;
21557        }
21558        self.addons
21559            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21560    }
21561
21562    pub fn unregister_addon<T: Addon>(&mut self) {
21563        self.addons.remove(&std::any::TypeId::of::<T>());
21564    }
21565
21566    pub fn addon<T: Addon>(&self) -> Option<&T> {
21567        let type_id = std::any::TypeId::of::<T>();
21568        self.addons
21569            .get(&type_id)
21570            .and_then(|item| item.to_any().downcast_ref::<T>())
21571    }
21572
21573    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21574        let type_id = std::any::TypeId::of::<T>();
21575        self.addons
21576            .get_mut(&type_id)
21577            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21578    }
21579
21580    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21581        let text_layout_details = self.text_layout_details(window);
21582        let style = &text_layout_details.editor_style;
21583        let font_id = window.text_system().resolve_font(&style.text.font());
21584        let font_size = style.text.font_size.to_pixels(window.rem_size());
21585        let line_height = style.text.line_height_in_pixels(window.rem_size());
21586        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21587        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21588
21589        CharacterDimensions {
21590            em_width,
21591            em_advance,
21592            line_height,
21593        }
21594    }
21595
21596    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21597        self.load_diff_task.clone()
21598    }
21599
21600    fn read_metadata_from_db(
21601        &mut self,
21602        item_id: u64,
21603        workspace_id: WorkspaceId,
21604        window: &mut Window,
21605        cx: &mut Context<Editor>,
21606    ) {
21607        if self.is_singleton(cx)
21608            && !self.mode.is_minimap()
21609            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21610        {
21611            let buffer_snapshot = OnceCell::new();
21612
21613            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21614                && !folds.is_empty()
21615            {
21616                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21617                self.fold_ranges(
21618                    folds
21619                        .into_iter()
21620                        .map(|(start, end)| {
21621                            snapshot.clip_offset(start, Bias::Left)
21622                                ..snapshot.clip_offset(end, Bias::Right)
21623                        })
21624                        .collect(),
21625                    false,
21626                    window,
21627                    cx,
21628                );
21629            }
21630
21631            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21632                && !selections.is_empty()
21633            {
21634                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21635                // skip adding the initial selection to selection history
21636                self.selection_history.mode = SelectionHistoryMode::Skipping;
21637                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21638                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21639                        snapshot.clip_offset(start, Bias::Left)
21640                            ..snapshot.clip_offset(end, Bias::Right)
21641                    }));
21642                });
21643                self.selection_history.mode = SelectionHistoryMode::Normal;
21644            };
21645        }
21646
21647        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21648    }
21649
21650    fn update_lsp_data(
21651        &mut self,
21652        ignore_cache: bool,
21653        for_buffer: Option<BufferId>,
21654        window: &mut Window,
21655        cx: &mut Context<'_, Self>,
21656    ) {
21657        self.pull_diagnostics(for_buffer, window, cx);
21658        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21659    }
21660}
21661
21662fn vim_enabled(cx: &App) -> bool {
21663    cx.global::<SettingsStore>()
21664        .raw_user_settings()
21665        .get("vim_mode")
21666        == Some(&serde_json::Value::Bool(true))
21667}
21668
21669fn process_completion_for_edit(
21670    completion: &Completion,
21671    intent: CompletionIntent,
21672    buffer: &Entity<Buffer>,
21673    cursor_position: &text::Anchor,
21674    cx: &mut Context<Editor>,
21675) -> CompletionEdit {
21676    let buffer = buffer.read(cx);
21677    let buffer_snapshot = buffer.snapshot();
21678    let (snippet, new_text) = if completion.is_snippet() {
21679        // Workaround for typescript language server issues so that methods don't expand within
21680        // strings and functions with type expressions. The previous point is used because the query
21681        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21682        let mut snippet_source = completion.new_text.clone();
21683        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21684        previous_point.column = previous_point.column.saturating_sub(1);
21685        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21686            && scope.prefers_label_for_snippet_in_completion()
21687            && let Some(label) = completion.label()
21688            && matches!(
21689                completion.kind(),
21690                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21691            )
21692        {
21693            snippet_source = label;
21694        }
21695        match Snippet::parse(&snippet_source).log_err() {
21696            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21697            None => (None, completion.new_text.clone()),
21698        }
21699    } else {
21700        (None, completion.new_text.clone())
21701    };
21702
21703    let mut range_to_replace = {
21704        let replace_range = &completion.replace_range;
21705        if let CompletionSource::Lsp {
21706            insert_range: Some(insert_range),
21707            ..
21708        } = &completion.source
21709        {
21710            debug_assert_eq!(
21711                insert_range.start, replace_range.start,
21712                "insert_range and replace_range should start at the same position"
21713            );
21714            debug_assert!(
21715                insert_range
21716                    .start
21717                    .cmp(cursor_position, &buffer_snapshot)
21718                    .is_le(),
21719                "insert_range should start before or at cursor position"
21720            );
21721            debug_assert!(
21722                replace_range
21723                    .start
21724                    .cmp(cursor_position, &buffer_snapshot)
21725                    .is_le(),
21726                "replace_range should start before or at cursor position"
21727            );
21728
21729            let should_replace = match intent {
21730                CompletionIntent::CompleteWithInsert => false,
21731                CompletionIntent::CompleteWithReplace => true,
21732                CompletionIntent::Complete | CompletionIntent::Compose => {
21733                    let insert_mode =
21734                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21735                            .completions
21736                            .lsp_insert_mode;
21737                    match insert_mode {
21738                        LspInsertMode::Insert => false,
21739                        LspInsertMode::Replace => true,
21740                        LspInsertMode::ReplaceSubsequence => {
21741                            let mut text_to_replace = buffer.chars_for_range(
21742                                buffer.anchor_before(replace_range.start)
21743                                    ..buffer.anchor_after(replace_range.end),
21744                            );
21745                            let mut current_needle = text_to_replace.next();
21746                            for haystack_ch in completion.label.text.chars() {
21747                                if let Some(needle_ch) = current_needle
21748                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21749                                {
21750                                    current_needle = text_to_replace.next();
21751                                }
21752                            }
21753                            current_needle.is_none()
21754                        }
21755                        LspInsertMode::ReplaceSuffix => {
21756                            if replace_range
21757                                .end
21758                                .cmp(cursor_position, &buffer_snapshot)
21759                                .is_gt()
21760                            {
21761                                let range_after_cursor = *cursor_position..replace_range.end;
21762                                let text_after_cursor = buffer
21763                                    .text_for_range(
21764                                        buffer.anchor_before(range_after_cursor.start)
21765                                            ..buffer.anchor_after(range_after_cursor.end),
21766                                    )
21767                                    .collect::<String>()
21768                                    .to_ascii_lowercase();
21769                                completion
21770                                    .label
21771                                    .text
21772                                    .to_ascii_lowercase()
21773                                    .ends_with(&text_after_cursor)
21774                            } else {
21775                                true
21776                            }
21777                        }
21778                    }
21779                }
21780            };
21781
21782            if should_replace {
21783                replace_range.clone()
21784            } else {
21785                insert_range.clone()
21786            }
21787        } else {
21788            replace_range.clone()
21789        }
21790    };
21791
21792    if range_to_replace
21793        .end
21794        .cmp(cursor_position, &buffer_snapshot)
21795        .is_lt()
21796    {
21797        range_to_replace.end = *cursor_position;
21798    }
21799
21800    CompletionEdit {
21801        new_text,
21802        replace_range: range_to_replace.to_offset(buffer),
21803        snippet,
21804    }
21805}
21806
21807struct CompletionEdit {
21808    new_text: String,
21809    replace_range: Range<usize>,
21810    snippet: Option<Snippet>,
21811}
21812
21813fn insert_extra_newline_brackets(
21814    buffer: &MultiBufferSnapshot,
21815    range: Range<usize>,
21816    language: &language::LanguageScope,
21817) -> bool {
21818    let leading_whitespace_len = buffer
21819        .reversed_chars_at(range.start)
21820        .take_while(|c| c.is_whitespace() && *c != '\n')
21821        .map(|c| c.len_utf8())
21822        .sum::<usize>();
21823    let trailing_whitespace_len = buffer
21824        .chars_at(range.end)
21825        .take_while(|c| c.is_whitespace() && *c != '\n')
21826        .map(|c| c.len_utf8())
21827        .sum::<usize>();
21828    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21829
21830    language.brackets().any(|(pair, enabled)| {
21831        let pair_start = pair.start.trim_end();
21832        let pair_end = pair.end.trim_start();
21833
21834        enabled
21835            && pair.newline
21836            && buffer.contains_str_at(range.end, pair_end)
21837            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21838    })
21839}
21840
21841fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21842    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21843        [(buffer, range, _)] => (*buffer, range.clone()),
21844        _ => return false,
21845    };
21846    let pair = {
21847        let mut result: Option<BracketMatch> = None;
21848
21849        for pair in buffer
21850            .all_bracket_ranges(range.clone())
21851            .filter(move |pair| {
21852                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21853            })
21854        {
21855            let len = pair.close_range.end - pair.open_range.start;
21856
21857            if let Some(existing) = &result {
21858                let existing_len = existing.close_range.end - existing.open_range.start;
21859                if len > existing_len {
21860                    continue;
21861                }
21862            }
21863
21864            result = Some(pair);
21865        }
21866
21867        result
21868    };
21869    let Some(pair) = pair else {
21870        return false;
21871    };
21872    pair.newline_only
21873        && buffer
21874            .chars_for_range(pair.open_range.end..range.start)
21875            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21876            .all(|c| c.is_whitespace() && c != '\n')
21877}
21878
21879fn update_uncommitted_diff_for_buffer(
21880    editor: Entity<Editor>,
21881    project: &Entity<Project>,
21882    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21883    buffer: Entity<MultiBuffer>,
21884    cx: &mut App,
21885) -> Task<()> {
21886    let mut tasks = Vec::new();
21887    project.update(cx, |project, cx| {
21888        for buffer in buffers {
21889            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21890                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21891            }
21892        }
21893    });
21894    cx.spawn(async move |cx| {
21895        let diffs = future::join_all(tasks).await;
21896        if editor
21897            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21898            .unwrap_or(false)
21899        {
21900            return;
21901        }
21902
21903        buffer
21904            .update(cx, |buffer, cx| {
21905                for diff in diffs.into_iter().flatten() {
21906                    buffer.add_diff(diff, cx);
21907                }
21908            })
21909            .ok();
21910    })
21911}
21912
21913fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21914    let tab_size = tab_size.get() as usize;
21915    let mut width = offset;
21916
21917    for ch in text.chars() {
21918        width += if ch == '\t' {
21919            tab_size - (width % tab_size)
21920        } else {
21921            1
21922        };
21923    }
21924
21925    width - offset
21926}
21927
21928#[cfg(test)]
21929mod tests {
21930    use super::*;
21931
21932    #[test]
21933    fn test_string_size_with_expanded_tabs() {
21934        let nz = |val| NonZeroU32::new(val).unwrap();
21935        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21936        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21937        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21938        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21939        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21940        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21941        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21942        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21943    }
21944}
21945
21946/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21947struct WordBreakingTokenizer<'a> {
21948    input: &'a str,
21949}
21950
21951impl<'a> WordBreakingTokenizer<'a> {
21952    fn new(input: &'a str) -> Self {
21953        Self { input }
21954    }
21955}
21956
21957fn is_char_ideographic(ch: char) -> bool {
21958    use unicode_script::Script::*;
21959    use unicode_script::UnicodeScript;
21960    matches!(ch.script(), Han | Tangut | Yi)
21961}
21962
21963fn is_grapheme_ideographic(text: &str) -> bool {
21964    text.chars().any(is_char_ideographic)
21965}
21966
21967fn is_grapheme_whitespace(text: &str) -> bool {
21968    text.chars().any(|x| x.is_whitespace())
21969}
21970
21971fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21972    text.chars()
21973        .next()
21974        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21975}
21976
21977#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21978enum WordBreakToken<'a> {
21979    Word { token: &'a str, grapheme_len: usize },
21980    InlineWhitespace { token: &'a str, grapheme_len: usize },
21981    Newline,
21982}
21983
21984impl<'a> Iterator for WordBreakingTokenizer<'a> {
21985    /// Yields a span, the count of graphemes in the token, and whether it was
21986    /// whitespace. Note that it also breaks at word boundaries.
21987    type Item = WordBreakToken<'a>;
21988
21989    fn next(&mut self) -> Option<Self::Item> {
21990        use unicode_segmentation::UnicodeSegmentation;
21991        if self.input.is_empty() {
21992            return None;
21993        }
21994
21995        let mut iter = self.input.graphemes(true).peekable();
21996        let mut offset = 0;
21997        let mut grapheme_len = 0;
21998        if let Some(first_grapheme) = iter.next() {
21999            let is_newline = first_grapheme == "\n";
22000            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22001            offset += first_grapheme.len();
22002            grapheme_len += 1;
22003            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22004                if let Some(grapheme) = iter.peek().copied()
22005                    && should_stay_with_preceding_ideograph(grapheme)
22006                {
22007                    offset += grapheme.len();
22008                    grapheme_len += 1;
22009                }
22010            } else {
22011                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22012                let mut next_word_bound = words.peek().copied();
22013                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22014                    next_word_bound = words.next();
22015                }
22016                while let Some(grapheme) = iter.peek().copied() {
22017                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22018                        break;
22019                    };
22020                    if is_grapheme_whitespace(grapheme) != is_whitespace
22021                        || (grapheme == "\n") != is_newline
22022                    {
22023                        break;
22024                    };
22025                    offset += grapheme.len();
22026                    grapheme_len += 1;
22027                    iter.next();
22028                }
22029            }
22030            let token = &self.input[..offset];
22031            self.input = &self.input[offset..];
22032            if token == "\n" {
22033                Some(WordBreakToken::Newline)
22034            } else if is_whitespace {
22035                Some(WordBreakToken::InlineWhitespace {
22036                    token,
22037                    grapheme_len,
22038                })
22039            } else {
22040                Some(WordBreakToken::Word {
22041                    token,
22042                    grapheme_len,
22043                })
22044            }
22045        } else {
22046            None
22047        }
22048    }
22049}
22050
22051#[test]
22052fn test_word_breaking_tokenizer() {
22053    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22054        ("", &[]),
22055        ("  ", &[whitespace("  ", 2)]),
22056        ("Ʒ", &[word("Ʒ", 1)]),
22057        ("Ǽ", &[word("Ǽ", 1)]),
22058        ("", &[word("", 1)]),
22059        ("⋑⋑", &[word("⋑⋑", 2)]),
22060        (
22061            "原理,进而",
22062            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22063        ),
22064        (
22065            "hello world",
22066            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22067        ),
22068        (
22069            "hello, world",
22070            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22071        ),
22072        (
22073            "  hello world",
22074            &[
22075                whitespace("  ", 2),
22076                word("hello", 5),
22077                whitespace(" ", 1),
22078                word("world", 5),
22079            ],
22080        ),
22081        (
22082            "这是什么 \n 钢笔",
22083            &[
22084                word("", 1),
22085                word("", 1),
22086                word("", 1),
22087                word("", 1),
22088                whitespace(" ", 1),
22089                newline(),
22090                whitespace(" ", 1),
22091                word("", 1),
22092                word("", 1),
22093            ],
22094        ),
22095        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22096    ];
22097
22098    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22099        WordBreakToken::Word {
22100            token,
22101            grapheme_len,
22102        }
22103    }
22104
22105    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22106        WordBreakToken::InlineWhitespace {
22107            token,
22108            grapheme_len,
22109        }
22110    }
22111
22112    fn newline() -> WordBreakToken<'static> {
22113        WordBreakToken::Newline
22114    }
22115
22116    for (input, result) in tests {
22117        assert_eq!(
22118            WordBreakingTokenizer::new(input)
22119                .collect::<Vec<_>>()
22120                .as_slice(),
22121            *result,
22122        );
22123    }
22124}
22125
22126fn wrap_with_prefix(
22127    first_line_prefix: String,
22128    subsequent_lines_prefix: String,
22129    unwrapped_text: String,
22130    wrap_column: usize,
22131    tab_size: NonZeroU32,
22132    preserve_existing_whitespace: bool,
22133) -> String {
22134    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22135    let subsequent_lines_prefix_len =
22136        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22137    let mut wrapped_text = String::new();
22138    let mut current_line = first_line_prefix;
22139    let mut is_first_line = true;
22140
22141    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22142    let mut current_line_len = first_line_prefix_len;
22143    let mut in_whitespace = false;
22144    for token in tokenizer {
22145        let have_preceding_whitespace = in_whitespace;
22146        match token {
22147            WordBreakToken::Word {
22148                token,
22149                grapheme_len,
22150            } => {
22151                in_whitespace = false;
22152                let current_prefix_len = if is_first_line {
22153                    first_line_prefix_len
22154                } else {
22155                    subsequent_lines_prefix_len
22156                };
22157                if current_line_len + grapheme_len > wrap_column
22158                    && current_line_len != current_prefix_len
22159                {
22160                    wrapped_text.push_str(current_line.trim_end());
22161                    wrapped_text.push('\n');
22162                    is_first_line = false;
22163                    current_line = subsequent_lines_prefix.clone();
22164                    current_line_len = subsequent_lines_prefix_len;
22165                }
22166                current_line.push_str(token);
22167                current_line_len += grapheme_len;
22168            }
22169            WordBreakToken::InlineWhitespace {
22170                mut token,
22171                mut grapheme_len,
22172            } => {
22173                in_whitespace = true;
22174                if have_preceding_whitespace && !preserve_existing_whitespace {
22175                    continue;
22176                }
22177                if !preserve_existing_whitespace {
22178                    token = " ";
22179                    grapheme_len = 1;
22180                }
22181                let current_prefix_len = if is_first_line {
22182                    first_line_prefix_len
22183                } else {
22184                    subsequent_lines_prefix_len
22185                };
22186                if current_line_len + grapheme_len > wrap_column {
22187                    wrapped_text.push_str(current_line.trim_end());
22188                    wrapped_text.push('\n');
22189                    is_first_line = false;
22190                    current_line = subsequent_lines_prefix.clone();
22191                    current_line_len = subsequent_lines_prefix_len;
22192                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22193                    current_line.push_str(token);
22194                    current_line_len += grapheme_len;
22195                }
22196            }
22197            WordBreakToken::Newline => {
22198                in_whitespace = true;
22199                let current_prefix_len = if is_first_line {
22200                    first_line_prefix_len
22201                } else {
22202                    subsequent_lines_prefix_len
22203                };
22204                if preserve_existing_whitespace {
22205                    wrapped_text.push_str(current_line.trim_end());
22206                    wrapped_text.push('\n');
22207                    is_first_line = false;
22208                    current_line = subsequent_lines_prefix.clone();
22209                    current_line_len = subsequent_lines_prefix_len;
22210                } else if have_preceding_whitespace {
22211                    continue;
22212                } else if current_line_len + 1 > wrap_column
22213                    && current_line_len != current_prefix_len
22214                {
22215                    wrapped_text.push_str(current_line.trim_end());
22216                    wrapped_text.push('\n');
22217                    is_first_line = false;
22218                    current_line = subsequent_lines_prefix.clone();
22219                    current_line_len = subsequent_lines_prefix_len;
22220                } else if current_line_len != current_prefix_len {
22221                    current_line.push(' ');
22222                    current_line_len += 1;
22223                }
22224            }
22225        }
22226    }
22227
22228    if !current_line.is_empty() {
22229        wrapped_text.push_str(&current_line);
22230    }
22231    wrapped_text
22232}
22233
22234#[test]
22235fn test_wrap_with_prefix() {
22236    assert_eq!(
22237        wrap_with_prefix(
22238            "# ".to_string(),
22239            "# ".to_string(),
22240            "abcdefg".to_string(),
22241            4,
22242            NonZeroU32::new(4).unwrap(),
22243            false,
22244        ),
22245        "# abcdefg"
22246    );
22247    assert_eq!(
22248        wrap_with_prefix(
22249            "".to_string(),
22250            "".to_string(),
22251            "\thello world".to_string(),
22252            8,
22253            NonZeroU32::new(4).unwrap(),
22254            false,
22255        ),
22256        "hello\nworld"
22257    );
22258    assert_eq!(
22259        wrap_with_prefix(
22260            "// ".to_string(),
22261            "// ".to_string(),
22262            "xx \nyy zz aa bb cc".to_string(),
22263            12,
22264            NonZeroU32::new(4).unwrap(),
22265            false,
22266        ),
22267        "// xx yy zz\n// aa bb cc"
22268    );
22269    assert_eq!(
22270        wrap_with_prefix(
22271            String::new(),
22272            String::new(),
22273            "这是什么 \n 钢笔".to_string(),
22274            3,
22275            NonZeroU32::new(4).unwrap(),
22276            false,
22277        ),
22278        "这是什\n么 钢\n"
22279    );
22280}
22281
22282pub trait CollaborationHub {
22283    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22284    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22285    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22286}
22287
22288impl CollaborationHub for Entity<Project> {
22289    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22290        self.read(cx).collaborators()
22291    }
22292
22293    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22294        self.read(cx).user_store().read(cx).participant_indices()
22295    }
22296
22297    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22298        let this = self.read(cx);
22299        let user_ids = this.collaborators().values().map(|c| c.user_id);
22300        this.user_store().read(cx).participant_names(user_ids, cx)
22301    }
22302}
22303
22304pub trait SemanticsProvider {
22305    fn hover(
22306        &self,
22307        buffer: &Entity<Buffer>,
22308        position: text::Anchor,
22309        cx: &mut App,
22310    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22311
22312    fn inline_values(
22313        &self,
22314        buffer_handle: Entity<Buffer>,
22315        range: Range<text::Anchor>,
22316        cx: &mut App,
22317    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22318
22319    fn inlay_hints(
22320        &self,
22321        buffer_handle: Entity<Buffer>,
22322        range: Range<text::Anchor>,
22323        cx: &mut App,
22324    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22325
22326    fn resolve_inlay_hint(
22327        &self,
22328        hint: InlayHint,
22329        buffer_handle: Entity<Buffer>,
22330        server_id: LanguageServerId,
22331        cx: &mut App,
22332    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22333
22334    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22335
22336    fn document_highlights(
22337        &self,
22338        buffer: &Entity<Buffer>,
22339        position: text::Anchor,
22340        cx: &mut App,
22341    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22342
22343    fn definitions(
22344        &self,
22345        buffer: &Entity<Buffer>,
22346        position: text::Anchor,
22347        kind: GotoDefinitionKind,
22348        cx: &mut App,
22349    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22350
22351    fn range_for_rename(
22352        &self,
22353        buffer: &Entity<Buffer>,
22354        position: text::Anchor,
22355        cx: &mut App,
22356    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22357
22358    fn perform_rename(
22359        &self,
22360        buffer: &Entity<Buffer>,
22361        position: text::Anchor,
22362        new_name: String,
22363        cx: &mut App,
22364    ) -> Option<Task<Result<ProjectTransaction>>>;
22365}
22366
22367pub trait CompletionProvider {
22368    fn completions(
22369        &self,
22370        excerpt_id: ExcerptId,
22371        buffer: &Entity<Buffer>,
22372        buffer_position: text::Anchor,
22373        trigger: CompletionContext,
22374        window: &mut Window,
22375        cx: &mut Context<Editor>,
22376    ) -> Task<Result<Vec<CompletionResponse>>>;
22377
22378    fn resolve_completions(
22379        &self,
22380        _buffer: Entity<Buffer>,
22381        _completion_indices: Vec<usize>,
22382        _completions: Rc<RefCell<Box<[Completion]>>>,
22383        _cx: &mut Context<Editor>,
22384    ) -> Task<Result<bool>> {
22385        Task::ready(Ok(false))
22386    }
22387
22388    fn apply_additional_edits_for_completion(
22389        &self,
22390        _buffer: Entity<Buffer>,
22391        _completions: Rc<RefCell<Box<[Completion]>>>,
22392        _completion_index: usize,
22393        _push_to_history: bool,
22394        _cx: &mut Context<Editor>,
22395    ) -> Task<Result<Option<language::Transaction>>> {
22396        Task::ready(Ok(None))
22397    }
22398
22399    fn is_completion_trigger(
22400        &self,
22401        buffer: &Entity<Buffer>,
22402        position: language::Anchor,
22403        text: &str,
22404        trigger_in_words: bool,
22405        menu_is_open: bool,
22406        cx: &mut Context<Editor>,
22407    ) -> bool;
22408
22409    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22410
22411    fn sort_completions(&self) -> bool {
22412        true
22413    }
22414
22415    fn filter_completions(&self) -> bool {
22416        true
22417    }
22418}
22419
22420pub trait CodeActionProvider {
22421    fn id(&self) -> Arc<str>;
22422
22423    fn code_actions(
22424        &self,
22425        buffer: &Entity<Buffer>,
22426        range: Range<text::Anchor>,
22427        window: &mut Window,
22428        cx: &mut App,
22429    ) -> Task<Result<Vec<CodeAction>>>;
22430
22431    fn apply_code_action(
22432        &self,
22433        buffer_handle: Entity<Buffer>,
22434        action: CodeAction,
22435        excerpt_id: ExcerptId,
22436        push_to_history: bool,
22437        window: &mut Window,
22438        cx: &mut App,
22439    ) -> Task<Result<ProjectTransaction>>;
22440}
22441
22442impl CodeActionProvider for Entity<Project> {
22443    fn id(&self) -> Arc<str> {
22444        "project".into()
22445    }
22446
22447    fn code_actions(
22448        &self,
22449        buffer: &Entity<Buffer>,
22450        range: Range<text::Anchor>,
22451        _window: &mut Window,
22452        cx: &mut App,
22453    ) -> Task<Result<Vec<CodeAction>>> {
22454        self.update(cx, |project, cx| {
22455            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22456            let code_actions = project.code_actions(buffer, range, None, cx);
22457            cx.background_spawn(async move {
22458                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22459                Ok(code_lens_actions
22460                    .context("code lens fetch")?
22461                    .into_iter()
22462                    .flatten()
22463                    .chain(
22464                        code_actions
22465                            .context("code action fetch")?
22466                            .into_iter()
22467                            .flatten(),
22468                    )
22469                    .collect())
22470            })
22471        })
22472    }
22473
22474    fn apply_code_action(
22475        &self,
22476        buffer_handle: Entity<Buffer>,
22477        action: CodeAction,
22478        _excerpt_id: ExcerptId,
22479        push_to_history: bool,
22480        _window: &mut Window,
22481        cx: &mut App,
22482    ) -> Task<Result<ProjectTransaction>> {
22483        self.update(cx, |project, cx| {
22484            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22485        })
22486    }
22487}
22488
22489fn snippet_completions(
22490    project: &Project,
22491    buffer: &Entity<Buffer>,
22492    buffer_position: text::Anchor,
22493    cx: &mut App,
22494) -> Task<Result<CompletionResponse>> {
22495    let languages = buffer.read(cx).languages_at(buffer_position);
22496    let snippet_store = project.snippets().read(cx);
22497
22498    let scopes: Vec<_> = languages
22499        .iter()
22500        .filter_map(|language| {
22501            let language_name = language.lsp_id();
22502            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22503
22504            if snippets.is_empty() {
22505                None
22506            } else {
22507                Some((language.default_scope(), snippets))
22508            }
22509        })
22510        .collect();
22511
22512    if scopes.is_empty() {
22513        return Task::ready(Ok(CompletionResponse {
22514            completions: vec![],
22515            display_options: CompletionDisplayOptions::default(),
22516            is_incomplete: false,
22517        }));
22518    }
22519
22520    let snapshot = buffer.read(cx).text_snapshot();
22521    let chars: String = snapshot
22522        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22523        .collect();
22524    let executor = cx.background_executor().clone();
22525
22526    cx.background_spawn(async move {
22527        let mut is_incomplete = false;
22528        let mut completions: Vec<Completion> = Vec::new();
22529        for (scope, snippets) in scopes.into_iter() {
22530            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22531            let mut last_word = chars
22532                .chars()
22533                .take_while(|c| classifier.is_word(*c))
22534                .collect::<String>();
22535            last_word = last_word.chars().rev().collect();
22536
22537            if last_word.is_empty() {
22538                return Ok(CompletionResponse {
22539                    completions: vec![],
22540                    display_options: CompletionDisplayOptions::default(),
22541                    is_incomplete: true,
22542                });
22543            }
22544
22545            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22546            let to_lsp = |point: &text::Anchor| {
22547                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22548                point_to_lsp(end)
22549            };
22550            let lsp_end = to_lsp(&buffer_position);
22551
22552            let candidates = snippets
22553                .iter()
22554                .enumerate()
22555                .flat_map(|(ix, snippet)| {
22556                    snippet
22557                        .prefix
22558                        .iter()
22559                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22560                })
22561                .collect::<Vec<StringMatchCandidate>>();
22562
22563            const MAX_RESULTS: usize = 100;
22564            let mut matches = fuzzy::match_strings(
22565                &candidates,
22566                &last_word,
22567                last_word.chars().any(|c| c.is_uppercase()),
22568                true,
22569                MAX_RESULTS,
22570                &Default::default(),
22571                executor.clone(),
22572            )
22573            .await;
22574
22575            if matches.len() >= MAX_RESULTS {
22576                is_incomplete = true;
22577            }
22578
22579            // Remove all candidates where the query's start does not match the start of any word in the candidate
22580            if let Some(query_start) = last_word.chars().next() {
22581                matches.retain(|string_match| {
22582                    split_words(&string_match.string).any(|word| {
22583                        // Check that the first codepoint of the word as lowercase matches the first
22584                        // codepoint of the query as lowercase
22585                        word.chars()
22586                            .flat_map(|codepoint| codepoint.to_lowercase())
22587                            .zip(query_start.to_lowercase())
22588                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22589                    })
22590                });
22591            }
22592
22593            let matched_strings = matches
22594                .into_iter()
22595                .map(|m| m.string)
22596                .collect::<HashSet<_>>();
22597
22598            completions.extend(snippets.iter().filter_map(|snippet| {
22599                let matching_prefix = snippet
22600                    .prefix
22601                    .iter()
22602                    .find(|prefix| matched_strings.contains(*prefix))?;
22603                let start = as_offset - last_word.len();
22604                let start = snapshot.anchor_before(start);
22605                let range = start..buffer_position;
22606                let lsp_start = to_lsp(&start);
22607                let lsp_range = lsp::Range {
22608                    start: lsp_start,
22609                    end: lsp_end,
22610                };
22611                Some(Completion {
22612                    replace_range: range,
22613                    new_text: snippet.body.clone(),
22614                    source: CompletionSource::Lsp {
22615                        insert_range: None,
22616                        server_id: LanguageServerId(usize::MAX),
22617                        resolved: true,
22618                        lsp_completion: Box::new(lsp::CompletionItem {
22619                            label: snippet.prefix.first().unwrap().clone(),
22620                            kind: Some(CompletionItemKind::SNIPPET),
22621                            label_details: snippet.description.as_ref().map(|description| {
22622                                lsp::CompletionItemLabelDetails {
22623                                    detail: Some(description.clone()),
22624                                    description: None,
22625                                }
22626                            }),
22627                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22628                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22629                                lsp::InsertReplaceEdit {
22630                                    new_text: snippet.body.clone(),
22631                                    insert: lsp_range,
22632                                    replace: lsp_range,
22633                                },
22634                            )),
22635                            filter_text: Some(snippet.body.clone()),
22636                            sort_text: Some(char::MAX.to_string()),
22637                            ..lsp::CompletionItem::default()
22638                        }),
22639                        lsp_defaults: None,
22640                    },
22641                    label: CodeLabel {
22642                        text: matching_prefix.clone(),
22643                        runs: Vec::new(),
22644                        filter_range: 0..matching_prefix.len(),
22645                    },
22646                    icon_path: None,
22647                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22648                        single_line: snippet.name.clone().into(),
22649                        plain_text: snippet
22650                            .description
22651                            .clone()
22652                            .map(|description| description.into()),
22653                    }),
22654                    insert_text_mode: None,
22655                    confirm: None,
22656                })
22657            }))
22658        }
22659
22660        Ok(CompletionResponse {
22661            completions,
22662            display_options: CompletionDisplayOptions::default(),
22663            is_incomplete,
22664        })
22665    })
22666}
22667
22668impl CompletionProvider for Entity<Project> {
22669    fn completions(
22670        &self,
22671        _excerpt_id: ExcerptId,
22672        buffer: &Entity<Buffer>,
22673        buffer_position: text::Anchor,
22674        options: CompletionContext,
22675        _window: &mut Window,
22676        cx: &mut Context<Editor>,
22677    ) -> Task<Result<Vec<CompletionResponse>>> {
22678        self.update(cx, |project, cx| {
22679            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22680            let project_completions = project.completions(buffer, buffer_position, options, cx);
22681            cx.background_spawn(async move {
22682                let mut responses = project_completions.await?;
22683                let snippets = snippets.await?;
22684                if !snippets.completions.is_empty() {
22685                    responses.push(snippets);
22686                }
22687                Ok(responses)
22688            })
22689        })
22690    }
22691
22692    fn resolve_completions(
22693        &self,
22694        buffer: Entity<Buffer>,
22695        completion_indices: Vec<usize>,
22696        completions: Rc<RefCell<Box<[Completion]>>>,
22697        cx: &mut Context<Editor>,
22698    ) -> Task<Result<bool>> {
22699        self.update(cx, |project, cx| {
22700            project.lsp_store().update(cx, |lsp_store, cx| {
22701                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22702            })
22703        })
22704    }
22705
22706    fn apply_additional_edits_for_completion(
22707        &self,
22708        buffer: Entity<Buffer>,
22709        completions: Rc<RefCell<Box<[Completion]>>>,
22710        completion_index: usize,
22711        push_to_history: bool,
22712        cx: &mut Context<Editor>,
22713    ) -> Task<Result<Option<language::Transaction>>> {
22714        self.update(cx, |project, cx| {
22715            project.lsp_store().update(cx, |lsp_store, cx| {
22716                lsp_store.apply_additional_edits_for_completion(
22717                    buffer,
22718                    completions,
22719                    completion_index,
22720                    push_to_history,
22721                    cx,
22722                )
22723            })
22724        })
22725    }
22726
22727    fn is_completion_trigger(
22728        &self,
22729        buffer: &Entity<Buffer>,
22730        position: language::Anchor,
22731        text: &str,
22732        trigger_in_words: bool,
22733        menu_is_open: bool,
22734        cx: &mut Context<Editor>,
22735    ) -> bool {
22736        let mut chars = text.chars();
22737        let char = if let Some(char) = chars.next() {
22738            char
22739        } else {
22740            return false;
22741        };
22742        if chars.next().is_some() {
22743            return false;
22744        }
22745
22746        let buffer = buffer.read(cx);
22747        let snapshot = buffer.snapshot();
22748        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22749            return false;
22750        }
22751        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22752        if trigger_in_words && classifier.is_word(char) {
22753            return true;
22754        }
22755
22756        buffer.completion_triggers().contains(text)
22757    }
22758}
22759
22760impl SemanticsProvider for Entity<Project> {
22761    fn hover(
22762        &self,
22763        buffer: &Entity<Buffer>,
22764        position: text::Anchor,
22765        cx: &mut App,
22766    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22767        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22768    }
22769
22770    fn document_highlights(
22771        &self,
22772        buffer: &Entity<Buffer>,
22773        position: text::Anchor,
22774        cx: &mut App,
22775    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22776        Some(self.update(cx, |project, cx| {
22777            project.document_highlights(buffer, position, cx)
22778        }))
22779    }
22780
22781    fn definitions(
22782        &self,
22783        buffer: &Entity<Buffer>,
22784        position: text::Anchor,
22785        kind: GotoDefinitionKind,
22786        cx: &mut App,
22787    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22788        Some(self.update(cx, |project, cx| match kind {
22789            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22790            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22791            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22792            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22793        }))
22794    }
22795
22796    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22797        self.update(cx, |project, cx| {
22798            if project
22799                .active_debug_session(cx)
22800                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22801            {
22802                return true;
22803            }
22804
22805            buffer.update(cx, |buffer, cx| {
22806                project.any_language_server_supports_inlay_hints(buffer, cx)
22807            })
22808        })
22809    }
22810
22811    fn inline_values(
22812        &self,
22813        buffer_handle: Entity<Buffer>,
22814        range: Range<text::Anchor>,
22815        cx: &mut App,
22816    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22817        self.update(cx, |project, cx| {
22818            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22819
22820            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22821        })
22822    }
22823
22824    fn inlay_hints(
22825        &self,
22826        buffer_handle: Entity<Buffer>,
22827        range: Range<text::Anchor>,
22828        cx: &mut App,
22829    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22830        Some(self.update(cx, |project, cx| {
22831            project.inlay_hints(buffer_handle, range, cx)
22832        }))
22833    }
22834
22835    fn resolve_inlay_hint(
22836        &self,
22837        hint: InlayHint,
22838        buffer_handle: Entity<Buffer>,
22839        server_id: LanguageServerId,
22840        cx: &mut App,
22841    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22842        Some(self.update(cx, |project, cx| {
22843            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22844        }))
22845    }
22846
22847    fn range_for_rename(
22848        &self,
22849        buffer: &Entity<Buffer>,
22850        position: text::Anchor,
22851        cx: &mut App,
22852    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22853        Some(self.update(cx, |project, cx| {
22854            let buffer = buffer.clone();
22855            let task = project.prepare_rename(buffer.clone(), position, cx);
22856            cx.spawn(async move |_, cx| {
22857                Ok(match task.await? {
22858                    PrepareRenameResponse::Success(range) => Some(range),
22859                    PrepareRenameResponse::InvalidPosition => None,
22860                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22861                        // Fallback on using TreeSitter info to determine identifier range
22862                        buffer.read_with(cx, |buffer, _| {
22863                            let snapshot = buffer.snapshot();
22864                            let (range, kind) = snapshot.surrounding_word(position, false);
22865                            if kind != Some(CharKind::Word) {
22866                                return None;
22867                            }
22868                            Some(
22869                                snapshot.anchor_before(range.start)
22870                                    ..snapshot.anchor_after(range.end),
22871                            )
22872                        })?
22873                    }
22874                })
22875            })
22876        }))
22877    }
22878
22879    fn perform_rename(
22880        &self,
22881        buffer: &Entity<Buffer>,
22882        position: text::Anchor,
22883        new_name: String,
22884        cx: &mut App,
22885    ) -> Option<Task<Result<ProjectTransaction>>> {
22886        Some(self.update(cx, |project, cx| {
22887            project.perform_rename(buffer.clone(), position, new_name, cx)
22888        }))
22889    }
22890}
22891
22892fn inlay_hint_settings(
22893    location: Anchor,
22894    snapshot: &MultiBufferSnapshot,
22895    cx: &mut Context<Editor>,
22896) -> InlayHintSettings {
22897    let file = snapshot.file_at(location);
22898    let language = snapshot.language_at(location).map(|l| l.name());
22899    language_settings(language, file, cx).inlay_hints
22900}
22901
22902fn consume_contiguous_rows(
22903    contiguous_row_selections: &mut Vec<Selection<Point>>,
22904    selection: &Selection<Point>,
22905    display_map: &DisplaySnapshot,
22906    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22907) -> (MultiBufferRow, MultiBufferRow) {
22908    contiguous_row_selections.push(selection.clone());
22909    let start_row = starting_row(selection, display_map);
22910    let mut end_row = ending_row(selection, display_map);
22911
22912    while let Some(next_selection) = selections.peek() {
22913        if next_selection.start.row <= end_row.0 {
22914            end_row = ending_row(next_selection, display_map);
22915            contiguous_row_selections.push(selections.next().unwrap().clone());
22916        } else {
22917            break;
22918        }
22919    }
22920    (start_row, end_row)
22921}
22922
22923fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22924    if selection.start.column > 0 {
22925        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22926    } else {
22927        MultiBufferRow(selection.start.row)
22928    }
22929}
22930
22931fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22932    if next_selection.end.column > 0 || next_selection.is_empty() {
22933        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22934    } else {
22935        MultiBufferRow(next_selection.end.row)
22936    }
22937}
22938
22939impl EditorSnapshot {
22940    pub fn remote_selections_in_range<'a>(
22941        &'a self,
22942        range: &'a Range<Anchor>,
22943        collaboration_hub: &dyn CollaborationHub,
22944        cx: &'a App,
22945    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22946        let participant_names = collaboration_hub.user_names(cx);
22947        let participant_indices = collaboration_hub.user_participant_indices(cx);
22948        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22949        let collaborators_by_replica_id = collaborators_by_peer_id
22950            .values()
22951            .map(|collaborator| (collaborator.replica_id, collaborator))
22952            .collect::<HashMap<_, _>>();
22953        self.buffer_snapshot
22954            .selections_in_range(range, false)
22955            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22956                if replica_id == AGENT_REPLICA_ID {
22957                    Some(RemoteSelection {
22958                        replica_id,
22959                        selection,
22960                        cursor_shape,
22961                        line_mode,
22962                        collaborator_id: CollaboratorId::Agent,
22963                        user_name: Some("Agent".into()),
22964                        color: cx.theme().players().agent(),
22965                    })
22966                } else {
22967                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22968                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22969                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22970                    Some(RemoteSelection {
22971                        replica_id,
22972                        selection,
22973                        cursor_shape,
22974                        line_mode,
22975                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22976                        user_name,
22977                        color: if let Some(index) = participant_index {
22978                            cx.theme().players().color_for_participant(index.0)
22979                        } else {
22980                            cx.theme().players().absent()
22981                        },
22982                    })
22983                }
22984            })
22985    }
22986
22987    pub fn hunks_for_ranges(
22988        &self,
22989        ranges: impl IntoIterator<Item = Range<Point>>,
22990    ) -> Vec<MultiBufferDiffHunk> {
22991        let mut hunks = Vec::new();
22992        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22993            HashMap::default();
22994        for query_range in ranges {
22995            let query_rows =
22996                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22997            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22998                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22999            ) {
23000                // Include deleted hunks that are adjacent to the query range, because
23001                // otherwise they would be missed.
23002                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23003                if hunk.status().is_deleted() {
23004                    intersects_range |= hunk.row_range.start == query_rows.end;
23005                    intersects_range |= hunk.row_range.end == query_rows.start;
23006                }
23007                if intersects_range {
23008                    if !processed_buffer_rows
23009                        .entry(hunk.buffer_id)
23010                        .or_default()
23011                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23012                    {
23013                        continue;
23014                    }
23015                    hunks.push(hunk);
23016                }
23017            }
23018        }
23019
23020        hunks
23021    }
23022
23023    fn display_diff_hunks_for_rows<'a>(
23024        &'a self,
23025        display_rows: Range<DisplayRow>,
23026        folded_buffers: &'a HashSet<BufferId>,
23027    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23028        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23029        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23030
23031        self.buffer_snapshot
23032            .diff_hunks_in_range(buffer_start..buffer_end)
23033            .filter_map(|hunk| {
23034                if folded_buffers.contains(&hunk.buffer_id) {
23035                    return None;
23036                }
23037
23038                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23039                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23040
23041                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23042                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23043
23044                let display_hunk = if hunk_display_start.column() != 0 {
23045                    DisplayDiffHunk::Folded {
23046                        display_row: hunk_display_start.row(),
23047                    }
23048                } else {
23049                    let mut end_row = hunk_display_end.row();
23050                    if hunk_display_end.column() > 0 {
23051                        end_row.0 += 1;
23052                    }
23053                    let is_created_file = hunk.is_created_file();
23054                    DisplayDiffHunk::Unfolded {
23055                        status: hunk.status(),
23056                        diff_base_byte_range: hunk.diff_base_byte_range,
23057                        display_row_range: hunk_display_start.row()..end_row,
23058                        multi_buffer_range: Anchor::range_in_buffer(
23059                            hunk.excerpt_id,
23060                            hunk.buffer_id,
23061                            hunk.buffer_range,
23062                        ),
23063                        is_created_file,
23064                    }
23065                };
23066
23067                Some(display_hunk)
23068            })
23069    }
23070
23071    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23072        self.display_snapshot.buffer_snapshot.language_at(position)
23073    }
23074
23075    pub fn is_focused(&self) -> bool {
23076        self.is_focused
23077    }
23078
23079    pub fn placeholder_text(&self) -> Option<String> {
23080        self.placeholder_display_snapshot
23081            .as_ref()
23082            .map(|display_map| display_map.text())
23083    }
23084
23085    pub fn scroll_position(&self) -> gpui::Point<f32> {
23086        self.scroll_anchor.scroll_position(&self.display_snapshot)
23087    }
23088
23089    fn gutter_dimensions(
23090        &self,
23091        font_id: FontId,
23092        font_size: Pixels,
23093        max_line_number_width: Pixels,
23094        cx: &App,
23095    ) -> Option<GutterDimensions> {
23096        if !self.show_gutter {
23097            return None;
23098        }
23099
23100        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23101        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23102
23103        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23104            matches!(
23105                ProjectSettings::get_global(cx).git.git_gutter,
23106                Some(GitGutterSetting::TrackedFiles)
23107            )
23108        });
23109        let gutter_settings = EditorSettings::get_global(cx).gutter;
23110        let show_line_numbers = self
23111            .show_line_numbers
23112            .unwrap_or(gutter_settings.line_numbers);
23113        let line_gutter_width = if show_line_numbers {
23114            // Avoid flicker-like gutter resizes when the line number gains another digit by
23115            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23116            let min_width_for_number_on_gutter =
23117                ch_advance * gutter_settings.min_line_number_digits as f32;
23118            max_line_number_width.max(min_width_for_number_on_gutter)
23119        } else {
23120            0.0.into()
23121        };
23122
23123        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23124        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23125
23126        let git_blame_entries_width =
23127            self.git_blame_gutter_max_author_length
23128                .map(|max_author_length| {
23129                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23130                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23131
23132                    /// The number of characters to dedicate to gaps and margins.
23133                    const SPACING_WIDTH: usize = 4;
23134
23135                    let max_char_count = max_author_length.min(renderer.max_author_length())
23136                        + ::git::SHORT_SHA_LENGTH
23137                        + MAX_RELATIVE_TIMESTAMP.len()
23138                        + SPACING_WIDTH;
23139
23140                    ch_advance * max_char_count
23141                });
23142
23143        let is_singleton = self.buffer_snapshot.is_singleton();
23144
23145        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23146        left_padding += if !is_singleton {
23147            ch_width * 4.0
23148        } else if show_runnables || show_breakpoints {
23149            ch_width * 3.0
23150        } else if show_git_gutter && show_line_numbers {
23151            ch_width * 2.0
23152        } else if show_git_gutter || show_line_numbers {
23153            ch_width
23154        } else {
23155            px(0.)
23156        };
23157
23158        let shows_folds = is_singleton && gutter_settings.folds;
23159
23160        let right_padding = if shows_folds && show_line_numbers {
23161            ch_width * 4.0
23162        } else if shows_folds || (!is_singleton && show_line_numbers) {
23163            ch_width * 3.0
23164        } else if show_line_numbers {
23165            ch_width
23166        } else {
23167            px(0.)
23168        };
23169
23170        Some(GutterDimensions {
23171            left_padding,
23172            right_padding,
23173            width: line_gutter_width + left_padding + right_padding,
23174            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23175            git_blame_entries_width,
23176        })
23177    }
23178
23179    pub fn render_crease_toggle(
23180        &self,
23181        buffer_row: MultiBufferRow,
23182        row_contains_cursor: bool,
23183        editor: Entity<Editor>,
23184        window: &mut Window,
23185        cx: &mut App,
23186    ) -> Option<AnyElement> {
23187        let folded = self.is_line_folded(buffer_row);
23188        let mut is_foldable = false;
23189
23190        if let Some(crease) = self
23191            .crease_snapshot
23192            .query_row(buffer_row, &self.buffer_snapshot)
23193        {
23194            is_foldable = true;
23195            match crease {
23196                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23197                    if let Some(render_toggle) = render_toggle {
23198                        let toggle_callback =
23199                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23200                                if folded {
23201                                    editor.update(cx, |editor, cx| {
23202                                        editor.fold_at(buffer_row, window, cx)
23203                                    });
23204                                } else {
23205                                    editor.update(cx, |editor, cx| {
23206                                        editor.unfold_at(buffer_row, window, cx)
23207                                    });
23208                                }
23209                            });
23210                        return Some((render_toggle)(
23211                            buffer_row,
23212                            folded,
23213                            toggle_callback,
23214                            window,
23215                            cx,
23216                        ));
23217                    }
23218                }
23219            }
23220        }
23221
23222        is_foldable |= self.starts_indent(buffer_row);
23223
23224        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23225            Some(
23226                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23227                    .toggle_state(folded)
23228                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23229                        if folded {
23230                            this.unfold_at(buffer_row, window, cx);
23231                        } else {
23232                            this.fold_at(buffer_row, window, cx);
23233                        }
23234                    }))
23235                    .into_any_element(),
23236            )
23237        } else {
23238            None
23239        }
23240    }
23241
23242    pub fn render_crease_trailer(
23243        &self,
23244        buffer_row: MultiBufferRow,
23245        window: &mut Window,
23246        cx: &mut App,
23247    ) -> Option<AnyElement> {
23248        let folded = self.is_line_folded(buffer_row);
23249        if let Crease::Inline { render_trailer, .. } = self
23250            .crease_snapshot
23251            .query_row(buffer_row, &self.buffer_snapshot)?
23252        {
23253            let render_trailer = render_trailer.as_ref()?;
23254            Some(render_trailer(buffer_row, folded, window, cx))
23255        } else {
23256            None
23257        }
23258    }
23259}
23260
23261impl Deref for EditorSnapshot {
23262    type Target = DisplaySnapshot;
23263
23264    fn deref(&self) -> &Self::Target {
23265        &self.display_snapshot
23266    }
23267}
23268
23269#[derive(Clone, Debug, PartialEq, Eq)]
23270pub enum EditorEvent {
23271    InputIgnored {
23272        text: Arc<str>,
23273    },
23274    InputHandled {
23275        utf16_range_to_replace: Option<Range<isize>>,
23276        text: Arc<str>,
23277    },
23278    ExcerptsAdded {
23279        buffer: Entity<Buffer>,
23280        predecessor: ExcerptId,
23281        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23282    },
23283    ExcerptsRemoved {
23284        ids: Vec<ExcerptId>,
23285        removed_buffer_ids: Vec<BufferId>,
23286    },
23287    BufferFoldToggled {
23288        ids: Vec<ExcerptId>,
23289        folded: bool,
23290    },
23291    ExcerptsEdited {
23292        ids: Vec<ExcerptId>,
23293    },
23294    ExcerptsExpanded {
23295        ids: Vec<ExcerptId>,
23296    },
23297    BufferEdited,
23298    Edited {
23299        transaction_id: clock::Lamport,
23300    },
23301    Reparsed(BufferId),
23302    Focused,
23303    FocusedIn,
23304    Blurred,
23305    DirtyChanged,
23306    Saved,
23307    TitleChanged,
23308    SelectionsChanged {
23309        local: bool,
23310    },
23311    ScrollPositionChanged {
23312        local: bool,
23313        autoscroll: bool,
23314    },
23315    TransactionUndone {
23316        transaction_id: clock::Lamport,
23317    },
23318    TransactionBegun {
23319        transaction_id: clock::Lamport,
23320    },
23321    CursorShapeChanged,
23322    BreadcrumbsChanged,
23323    PushedToNavHistory {
23324        anchor: Anchor,
23325        is_deactivate: bool,
23326    },
23327}
23328
23329impl EventEmitter<EditorEvent> for Editor {}
23330
23331impl Focusable for Editor {
23332    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23333        self.focus_handle.clone()
23334    }
23335}
23336
23337impl Render for Editor {
23338    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23339        let settings = ThemeSettings::get_global(cx);
23340
23341        let mut text_style = match self.mode {
23342            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23343                color: cx.theme().colors().editor_foreground,
23344                font_family: settings.ui_font.family.clone(),
23345                font_features: settings.ui_font.features.clone(),
23346                font_fallbacks: settings.ui_font.fallbacks.clone(),
23347                font_size: rems(0.875).into(),
23348                font_weight: settings.ui_font.weight,
23349                line_height: relative(settings.buffer_line_height.value()),
23350                ..Default::default()
23351            },
23352            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23353                color: cx.theme().colors().editor_foreground,
23354                font_family: settings.buffer_font.family.clone(),
23355                font_features: settings.buffer_font.features.clone(),
23356                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23357                font_size: settings.buffer_font_size(cx).into(),
23358                font_weight: settings.buffer_font.weight,
23359                line_height: relative(settings.buffer_line_height.value()),
23360                ..Default::default()
23361            },
23362        };
23363        if let Some(text_style_refinement) = &self.text_style_refinement {
23364            text_style.refine(text_style_refinement)
23365        }
23366
23367        let background = match self.mode {
23368            EditorMode::SingleLine => cx.theme().system().transparent,
23369            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23370            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23371            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23372        };
23373
23374        EditorElement::new(
23375            &cx.entity(),
23376            EditorStyle {
23377                background,
23378                border: cx.theme().colors().border,
23379                local_player: cx.theme().players().local(),
23380                text: text_style,
23381                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23382                syntax: cx.theme().syntax().clone(),
23383                status: cx.theme().status().clone(),
23384                inlay_hints_style: make_inlay_hints_style(cx),
23385                edit_prediction_styles: make_suggestion_styles(cx),
23386                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23387                show_underlines: self.diagnostics_enabled(),
23388            },
23389        )
23390    }
23391}
23392
23393impl EntityInputHandler for Editor {
23394    fn text_for_range(
23395        &mut self,
23396        range_utf16: Range<usize>,
23397        adjusted_range: &mut Option<Range<usize>>,
23398        _: &mut Window,
23399        cx: &mut Context<Self>,
23400    ) -> Option<String> {
23401        let snapshot = self.buffer.read(cx).read(cx);
23402        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23403        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23404        if (start.0..end.0) != range_utf16 {
23405            adjusted_range.replace(start.0..end.0);
23406        }
23407        Some(snapshot.text_for_range(start..end).collect())
23408    }
23409
23410    fn selected_text_range(
23411        &mut self,
23412        ignore_disabled_input: bool,
23413        _: &mut Window,
23414        cx: &mut Context<Self>,
23415    ) -> Option<UTF16Selection> {
23416        // Prevent the IME menu from appearing when holding down an alphabetic key
23417        // while input is disabled.
23418        if !ignore_disabled_input && !self.input_enabled {
23419            return None;
23420        }
23421
23422        let selection = self.selections.newest::<OffsetUtf16>(cx);
23423        let range = selection.range();
23424
23425        Some(UTF16Selection {
23426            range: range.start.0..range.end.0,
23427            reversed: selection.reversed,
23428        })
23429    }
23430
23431    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23432        let snapshot = self.buffer.read(cx).read(cx);
23433        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23434        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23435    }
23436
23437    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23438        self.clear_highlights::<InputComposition>(cx);
23439        self.ime_transaction.take();
23440    }
23441
23442    fn replace_text_in_range(
23443        &mut self,
23444        range_utf16: Option<Range<usize>>,
23445        text: &str,
23446        window: &mut Window,
23447        cx: &mut Context<Self>,
23448    ) {
23449        if !self.input_enabled {
23450            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23451            return;
23452        }
23453
23454        self.transact(window, cx, |this, window, cx| {
23455            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23456                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23457                Some(this.selection_replacement_ranges(range_utf16, cx))
23458            } else {
23459                this.marked_text_ranges(cx)
23460            };
23461
23462            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23463                let newest_selection_id = this.selections.newest_anchor().id;
23464                this.selections
23465                    .all::<OffsetUtf16>(cx)
23466                    .iter()
23467                    .zip(ranges_to_replace.iter())
23468                    .find_map(|(selection, range)| {
23469                        if selection.id == newest_selection_id {
23470                            Some(
23471                                (range.start.0 as isize - selection.head().0 as isize)
23472                                    ..(range.end.0 as isize - selection.head().0 as isize),
23473                            )
23474                        } else {
23475                            None
23476                        }
23477                    })
23478            });
23479
23480            cx.emit(EditorEvent::InputHandled {
23481                utf16_range_to_replace: range_to_replace,
23482                text: text.into(),
23483            });
23484
23485            if let Some(new_selected_ranges) = new_selected_ranges {
23486                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23487                    selections.select_ranges(new_selected_ranges)
23488                });
23489                this.backspace(&Default::default(), window, cx);
23490            }
23491
23492            this.handle_input(text, window, cx);
23493        });
23494
23495        if let Some(transaction) = self.ime_transaction {
23496            self.buffer.update(cx, |buffer, cx| {
23497                buffer.group_until_transaction(transaction, cx);
23498            });
23499        }
23500
23501        self.unmark_text(window, cx);
23502    }
23503
23504    fn replace_and_mark_text_in_range(
23505        &mut self,
23506        range_utf16: Option<Range<usize>>,
23507        text: &str,
23508        new_selected_range_utf16: Option<Range<usize>>,
23509        window: &mut Window,
23510        cx: &mut Context<Self>,
23511    ) {
23512        if !self.input_enabled {
23513            return;
23514        }
23515
23516        let transaction = self.transact(window, cx, |this, window, cx| {
23517            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23518                let snapshot = this.buffer.read(cx).read(cx);
23519                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23520                    for marked_range in &mut marked_ranges {
23521                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23522                        marked_range.start.0 += relative_range_utf16.start;
23523                        marked_range.start =
23524                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23525                        marked_range.end =
23526                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23527                    }
23528                }
23529                Some(marked_ranges)
23530            } else if let Some(range_utf16) = range_utf16 {
23531                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23532                Some(this.selection_replacement_ranges(range_utf16, cx))
23533            } else {
23534                None
23535            };
23536
23537            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23538                let newest_selection_id = this.selections.newest_anchor().id;
23539                this.selections
23540                    .all::<OffsetUtf16>(cx)
23541                    .iter()
23542                    .zip(ranges_to_replace.iter())
23543                    .find_map(|(selection, range)| {
23544                        if selection.id == newest_selection_id {
23545                            Some(
23546                                (range.start.0 as isize - selection.head().0 as isize)
23547                                    ..(range.end.0 as isize - selection.head().0 as isize),
23548                            )
23549                        } else {
23550                            None
23551                        }
23552                    })
23553            });
23554
23555            cx.emit(EditorEvent::InputHandled {
23556                utf16_range_to_replace: range_to_replace,
23557                text: text.into(),
23558            });
23559
23560            if let Some(ranges) = ranges_to_replace {
23561                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23562                    s.select_ranges(ranges)
23563                });
23564            }
23565
23566            let marked_ranges = {
23567                let snapshot = this.buffer.read(cx).read(cx);
23568                this.selections
23569                    .disjoint_anchors()
23570                    .iter()
23571                    .map(|selection| {
23572                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23573                    })
23574                    .collect::<Vec<_>>()
23575            };
23576
23577            if text.is_empty() {
23578                this.unmark_text(window, cx);
23579            } else {
23580                this.highlight_text::<InputComposition>(
23581                    marked_ranges.clone(),
23582                    HighlightStyle {
23583                        underline: Some(UnderlineStyle {
23584                            thickness: px(1.),
23585                            color: None,
23586                            wavy: false,
23587                        }),
23588                        ..Default::default()
23589                    },
23590                    cx,
23591                );
23592            }
23593
23594            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23595            let use_autoclose = this.use_autoclose;
23596            let use_auto_surround = this.use_auto_surround;
23597            this.set_use_autoclose(false);
23598            this.set_use_auto_surround(false);
23599            this.handle_input(text, window, cx);
23600            this.set_use_autoclose(use_autoclose);
23601            this.set_use_auto_surround(use_auto_surround);
23602
23603            if let Some(new_selected_range) = new_selected_range_utf16 {
23604                let snapshot = this.buffer.read(cx).read(cx);
23605                let new_selected_ranges = marked_ranges
23606                    .into_iter()
23607                    .map(|marked_range| {
23608                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23609                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23610                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23611                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23612                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23613                    })
23614                    .collect::<Vec<_>>();
23615
23616                drop(snapshot);
23617                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23618                    selections.select_ranges(new_selected_ranges)
23619                });
23620            }
23621        });
23622
23623        self.ime_transaction = self.ime_transaction.or(transaction);
23624        if let Some(transaction) = self.ime_transaction {
23625            self.buffer.update(cx, |buffer, cx| {
23626                buffer.group_until_transaction(transaction, cx);
23627            });
23628        }
23629
23630        if self.text_highlights::<InputComposition>(cx).is_none() {
23631            self.ime_transaction.take();
23632        }
23633    }
23634
23635    fn bounds_for_range(
23636        &mut self,
23637        range_utf16: Range<usize>,
23638        element_bounds: gpui::Bounds<Pixels>,
23639        window: &mut Window,
23640        cx: &mut Context<Self>,
23641    ) -> Option<gpui::Bounds<Pixels>> {
23642        let text_layout_details = self.text_layout_details(window);
23643        let CharacterDimensions {
23644            em_width,
23645            em_advance,
23646            line_height,
23647        } = self.character_dimensions(window);
23648
23649        let snapshot = self.snapshot(window, cx);
23650        let scroll_position = snapshot.scroll_position();
23651        let scroll_left = scroll_position.x * em_advance;
23652
23653        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23654        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23655            + self.gutter_dimensions.full_width();
23656        let y = line_height * (start.row().as_f32() - scroll_position.y);
23657
23658        Some(Bounds {
23659            origin: element_bounds.origin + point(x, y),
23660            size: size(em_width, line_height),
23661        })
23662    }
23663
23664    fn character_index_for_point(
23665        &mut self,
23666        point: gpui::Point<Pixels>,
23667        _window: &mut Window,
23668        _cx: &mut Context<Self>,
23669    ) -> Option<usize> {
23670        let position_map = self.last_position_map.as_ref()?;
23671        if !position_map.text_hitbox.contains(&point) {
23672            return None;
23673        }
23674        let display_point = position_map.point_for_position(point).previous_valid;
23675        let anchor = position_map
23676            .snapshot
23677            .display_point_to_anchor(display_point, Bias::Left);
23678        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23679        Some(utf16_offset.0)
23680    }
23681}
23682
23683trait SelectionExt {
23684    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23685    fn spanned_rows(
23686        &self,
23687        include_end_if_at_line_start: bool,
23688        map: &DisplaySnapshot,
23689    ) -> Range<MultiBufferRow>;
23690}
23691
23692impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23693    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23694        let start = self
23695            .start
23696            .to_point(&map.buffer_snapshot)
23697            .to_display_point(map);
23698        let end = self
23699            .end
23700            .to_point(&map.buffer_snapshot)
23701            .to_display_point(map);
23702        if self.reversed {
23703            end..start
23704        } else {
23705            start..end
23706        }
23707    }
23708
23709    fn spanned_rows(
23710        &self,
23711        include_end_if_at_line_start: bool,
23712        map: &DisplaySnapshot,
23713    ) -> Range<MultiBufferRow> {
23714        let start = self.start.to_point(&map.buffer_snapshot);
23715        let mut end = self.end.to_point(&map.buffer_snapshot);
23716        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23717            end.row -= 1;
23718        }
23719
23720        let buffer_start = map.prev_line_boundary(start).0;
23721        let buffer_end = map.next_line_boundary(end).0;
23722        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23723    }
23724}
23725
23726impl<T: InvalidationRegion> InvalidationStack<T> {
23727    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23728    where
23729        S: Clone + ToOffset,
23730    {
23731        while let Some(region) = self.last() {
23732            let all_selections_inside_invalidation_ranges =
23733                if selections.len() == region.ranges().len() {
23734                    selections
23735                        .iter()
23736                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23737                        .all(|(selection, invalidation_range)| {
23738                            let head = selection.head().to_offset(buffer);
23739                            invalidation_range.start <= head && invalidation_range.end >= head
23740                        })
23741                } else {
23742                    false
23743                };
23744
23745            if all_selections_inside_invalidation_ranges {
23746                break;
23747            } else {
23748                self.pop();
23749            }
23750        }
23751    }
23752}
23753
23754impl<T> Default for InvalidationStack<T> {
23755    fn default() -> Self {
23756        Self(Default::default())
23757    }
23758}
23759
23760impl<T> Deref for InvalidationStack<T> {
23761    type Target = Vec<T>;
23762
23763    fn deref(&self) -> &Self::Target {
23764        &self.0
23765    }
23766}
23767
23768impl<T> DerefMut for InvalidationStack<T> {
23769    fn deref_mut(&mut self) -> &mut Self::Target {
23770        &mut self.0
23771    }
23772}
23773
23774impl InvalidationRegion for SnippetState {
23775    fn ranges(&self) -> &[Range<Anchor>] {
23776        &self.ranges[self.active_index]
23777    }
23778}
23779
23780fn edit_prediction_edit_text(
23781    current_snapshot: &BufferSnapshot,
23782    edits: &[(Range<Anchor>, String)],
23783    edit_preview: &EditPreview,
23784    include_deletions: bool,
23785    cx: &App,
23786) -> HighlightedText {
23787    let edits = edits
23788        .iter()
23789        .map(|(anchor, text)| {
23790            (
23791                anchor.start.text_anchor..anchor.end.text_anchor,
23792                text.clone(),
23793            )
23794        })
23795        .collect::<Vec<_>>();
23796
23797    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23798}
23799
23800fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23801    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23802    // Just show the raw edit text with basic styling
23803    let mut text = String::new();
23804    let mut highlights = Vec::new();
23805
23806    let insertion_highlight_style = HighlightStyle {
23807        color: Some(cx.theme().colors().text),
23808        ..Default::default()
23809    };
23810
23811    for (_, edit_text) in edits {
23812        let start_offset = text.len();
23813        text.push_str(edit_text);
23814        let end_offset = text.len();
23815
23816        if start_offset < end_offset {
23817            highlights.push((start_offset..end_offset, insertion_highlight_style));
23818        }
23819    }
23820
23821    HighlightedText {
23822        text: text.into(),
23823        highlights,
23824    }
23825}
23826
23827pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23828    match severity {
23829        lsp::DiagnosticSeverity::ERROR => colors.error,
23830        lsp::DiagnosticSeverity::WARNING => colors.warning,
23831        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23832        lsp::DiagnosticSeverity::HINT => colors.info,
23833        _ => colors.ignored,
23834    }
23835}
23836
23837pub fn styled_runs_for_code_label<'a>(
23838    label: &'a CodeLabel,
23839    syntax_theme: &'a theme::SyntaxTheme,
23840) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23841    let fade_out = HighlightStyle {
23842        fade_out: Some(0.35),
23843        ..Default::default()
23844    };
23845
23846    let mut prev_end = label.filter_range.end;
23847    label
23848        .runs
23849        .iter()
23850        .enumerate()
23851        .flat_map(move |(ix, (range, highlight_id))| {
23852            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23853                style
23854            } else {
23855                return Default::default();
23856            };
23857            let muted_style = style.highlight(fade_out);
23858
23859            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23860            if range.start >= label.filter_range.end {
23861                if range.start > prev_end {
23862                    runs.push((prev_end..range.start, fade_out));
23863                }
23864                runs.push((range.clone(), muted_style));
23865            } else if range.end <= label.filter_range.end {
23866                runs.push((range.clone(), style));
23867            } else {
23868                runs.push((range.start..label.filter_range.end, style));
23869                runs.push((label.filter_range.end..range.end, muted_style));
23870            }
23871            prev_end = cmp::max(prev_end, range.end);
23872
23873            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23874                runs.push((prev_end..label.text.len(), fade_out));
23875            }
23876
23877            runs
23878        })
23879}
23880
23881pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23882    let mut prev_index = 0;
23883    let mut prev_codepoint: Option<char> = None;
23884    text.char_indices()
23885        .chain([(text.len(), '\0')])
23886        .filter_map(move |(index, codepoint)| {
23887            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23888            let is_boundary = index == text.len()
23889                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23890                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23891            if is_boundary {
23892                let chunk = &text[prev_index..index];
23893                prev_index = index;
23894                Some(chunk)
23895            } else {
23896                None
23897            }
23898        })
23899}
23900
23901pub trait RangeToAnchorExt: Sized {
23902    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23903
23904    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23905        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23906        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23907    }
23908}
23909
23910impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23911    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23912        let start_offset = self.start.to_offset(snapshot);
23913        let end_offset = self.end.to_offset(snapshot);
23914        if start_offset == end_offset {
23915            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23916        } else {
23917            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23918        }
23919    }
23920}
23921
23922pub trait RowExt {
23923    fn as_f32(&self) -> f32;
23924
23925    fn next_row(&self) -> Self;
23926
23927    fn previous_row(&self) -> Self;
23928
23929    fn minus(&self, other: Self) -> u32;
23930}
23931
23932impl RowExt for DisplayRow {
23933    fn as_f32(&self) -> f32 {
23934        self.0 as f32
23935    }
23936
23937    fn next_row(&self) -> Self {
23938        Self(self.0 + 1)
23939    }
23940
23941    fn previous_row(&self) -> Self {
23942        Self(self.0.saturating_sub(1))
23943    }
23944
23945    fn minus(&self, other: Self) -> u32 {
23946        self.0 - other.0
23947    }
23948}
23949
23950impl RowExt for MultiBufferRow {
23951    fn as_f32(&self) -> f32 {
23952        self.0 as f32
23953    }
23954
23955    fn next_row(&self) -> Self {
23956        Self(self.0 + 1)
23957    }
23958
23959    fn previous_row(&self) -> Self {
23960        Self(self.0.saturating_sub(1))
23961    }
23962
23963    fn minus(&self, other: Self) -> u32 {
23964        self.0 - other.0
23965    }
23966}
23967
23968trait RowRangeExt {
23969    type Row;
23970
23971    fn len(&self) -> usize;
23972
23973    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23974}
23975
23976impl RowRangeExt for Range<MultiBufferRow> {
23977    type Row = MultiBufferRow;
23978
23979    fn len(&self) -> usize {
23980        (self.end.0 - self.start.0) as usize
23981    }
23982
23983    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23984        (self.start.0..self.end.0).map(MultiBufferRow)
23985    }
23986}
23987
23988impl RowRangeExt for Range<DisplayRow> {
23989    type Row = DisplayRow;
23990
23991    fn len(&self) -> usize {
23992        (self.end.0 - self.start.0) as usize
23993    }
23994
23995    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23996        (self.start.0..self.end.0).map(DisplayRow)
23997    }
23998}
23999
24000/// If select range has more than one line, we
24001/// just point the cursor to range.start.
24002fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24003    if range.start.row == range.end.row {
24004        range
24005    } else {
24006        range.start..range.start
24007    }
24008}
24009pub struct KillRing(ClipboardItem);
24010impl Global for KillRing {}
24011
24012const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24013
24014enum BreakpointPromptEditAction {
24015    Log,
24016    Condition,
24017    HitCondition,
24018}
24019
24020struct BreakpointPromptEditor {
24021    pub(crate) prompt: Entity<Editor>,
24022    editor: WeakEntity<Editor>,
24023    breakpoint_anchor: Anchor,
24024    breakpoint: Breakpoint,
24025    edit_action: BreakpointPromptEditAction,
24026    block_ids: HashSet<CustomBlockId>,
24027    editor_margins: Arc<Mutex<EditorMargins>>,
24028    _subscriptions: Vec<Subscription>,
24029}
24030
24031impl BreakpointPromptEditor {
24032    const MAX_LINES: u8 = 4;
24033
24034    fn new(
24035        editor: WeakEntity<Editor>,
24036        breakpoint_anchor: Anchor,
24037        breakpoint: Breakpoint,
24038        edit_action: BreakpointPromptEditAction,
24039        window: &mut Window,
24040        cx: &mut Context<Self>,
24041    ) -> Self {
24042        let base_text = match edit_action {
24043            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24044            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24045            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24046        }
24047        .map(|msg| msg.to_string())
24048        .unwrap_or_default();
24049
24050        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24051        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24052
24053        let prompt = cx.new(|cx| {
24054            let mut prompt = Editor::new(
24055                EditorMode::AutoHeight {
24056                    min_lines: 1,
24057                    max_lines: Some(Self::MAX_LINES as usize),
24058                },
24059                buffer,
24060                None,
24061                window,
24062                cx,
24063            );
24064            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24065            prompt.set_show_cursor_when_unfocused(false, cx);
24066            prompt.set_placeholder_text(
24067                match edit_action {
24068                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24069                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24070                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24071                },
24072                window,
24073                cx,
24074            );
24075
24076            prompt
24077        });
24078
24079        Self {
24080            prompt,
24081            editor,
24082            breakpoint_anchor,
24083            breakpoint,
24084            edit_action,
24085            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24086            block_ids: Default::default(),
24087            _subscriptions: vec![],
24088        }
24089    }
24090
24091    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24092        self.block_ids.extend(block_ids)
24093    }
24094
24095    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24096        if let Some(editor) = self.editor.upgrade() {
24097            let message = self
24098                .prompt
24099                .read(cx)
24100                .buffer
24101                .read(cx)
24102                .as_singleton()
24103                .expect("A multi buffer in breakpoint prompt isn't possible")
24104                .read(cx)
24105                .as_rope()
24106                .to_string();
24107
24108            editor.update(cx, |editor, cx| {
24109                editor.edit_breakpoint_at_anchor(
24110                    self.breakpoint_anchor,
24111                    self.breakpoint.clone(),
24112                    match self.edit_action {
24113                        BreakpointPromptEditAction::Log => {
24114                            BreakpointEditAction::EditLogMessage(message.into())
24115                        }
24116                        BreakpointPromptEditAction::Condition => {
24117                            BreakpointEditAction::EditCondition(message.into())
24118                        }
24119                        BreakpointPromptEditAction::HitCondition => {
24120                            BreakpointEditAction::EditHitCondition(message.into())
24121                        }
24122                    },
24123                    cx,
24124                );
24125
24126                editor.remove_blocks(self.block_ids.clone(), None, cx);
24127                cx.focus_self(window);
24128            });
24129        }
24130    }
24131
24132    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24133        self.editor
24134            .update(cx, |editor, cx| {
24135                editor.remove_blocks(self.block_ids.clone(), None, cx);
24136                window.focus(&editor.focus_handle);
24137            })
24138            .log_err();
24139    }
24140
24141    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24142        let settings = ThemeSettings::get_global(cx);
24143        let text_style = TextStyle {
24144            color: if self.prompt.read(cx).read_only(cx) {
24145                cx.theme().colors().text_disabled
24146            } else {
24147                cx.theme().colors().text
24148            },
24149            font_family: settings.buffer_font.family.clone(),
24150            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24151            font_size: settings.buffer_font_size(cx).into(),
24152            font_weight: settings.buffer_font.weight,
24153            line_height: relative(settings.buffer_line_height.value()),
24154            ..Default::default()
24155        };
24156        EditorElement::new(
24157            &self.prompt,
24158            EditorStyle {
24159                background: cx.theme().colors().editor_background,
24160                local_player: cx.theme().players().local(),
24161                text: text_style,
24162                ..Default::default()
24163            },
24164        )
24165    }
24166}
24167
24168impl Render for BreakpointPromptEditor {
24169    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24170        let editor_margins = *self.editor_margins.lock();
24171        let gutter_dimensions = editor_margins.gutter;
24172        h_flex()
24173            .key_context("Editor")
24174            .bg(cx.theme().colors().editor_background)
24175            .border_y_1()
24176            .border_color(cx.theme().status().info_border)
24177            .size_full()
24178            .py(window.line_height() / 2.5)
24179            .on_action(cx.listener(Self::confirm))
24180            .on_action(cx.listener(Self::cancel))
24181            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24182            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24183    }
24184}
24185
24186impl Focusable for BreakpointPromptEditor {
24187    fn focus_handle(&self, cx: &App) -> FocusHandle {
24188        self.prompt.focus_handle(cx)
24189    }
24190}
24191
24192fn all_edits_insertions_or_deletions(
24193    edits: &Vec<(Range<Anchor>, String)>,
24194    snapshot: &MultiBufferSnapshot,
24195) -> bool {
24196    let mut all_insertions = true;
24197    let mut all_deletions = true;
24198
24199    for (range, new_text) in edits.iter() {
24200        let range_is_empty = range.to_offset(snapshot).is_empty();
24201        let text_is_empty = new_text.is_empty();
24202
24203        if range_is_empty != text_is_empty {
24204            if range_is_empty {
24205                all_deletions = false;
24206            } else {
24207                all_insertions = false;
24208            }
24209        } else {
24210            return false;
24211        }
24212
24213        if !all_insertions && !all_deletions {
24214            return false;
24215        }
24216    }
24217    all_insertions || all_deletions
24218}
24219
24220struct MissingEditPredictionKeybindingTooltip;
24221
24222impl Render for MissingEditPredictionKeybindingTooltip {
24223    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24224        ui::tooltip_container(window, cx, |container, _, cx| {
24225            container
24226                .flex_shrink_0()
24227                .max_w_80()
24228                .min_h(rems_from_px(124.))
24229                .justify_between()
24230                .child(
24231                    v_flex()
24232                        .flex_1()
24233                        .text_ui_sm(cx)
24234                        .child(Label::new("Conflict with Accept Keybinding"))
24235                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24236                )
24237                .child(
24238                    h_flex()
24239                        .pb_1()
24240                        .gap_1()
24241                        .items_end()
24242                        .w_full()
24243                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24244                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24245                        }))
24246                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24247                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24248                        })),
24249                )
24250        })
24251    }
24252}
24253
24254#[derive(Debug, Clone, Copy, PartialEq)]
24255pub struct LineHighlight {
24256    pub background: Background,
24257    pub border: Option<gpui::Hsla>,
24258    pub include_gutter: bool,
24259    pub type_id: Option<TypeId>,
24260}
24261
24262struct LineManipulationResult {
24263    pub new_text: String,
24264    pub line_count_before: usize,
24265    pub line_count_after: usize,
24266}
24267
24268fn render_diff_hunk_controls(
24269    row: u32,
24270    status: &DiffHunkStatus,
24271    hunk_range: Range<Anchor>,
24272    is_created_file: bool,
24273    line_height: Pixels,
24274    editor: &Entity<Editor>,
24275    _window: &mut Window,
24276    cx: &mut App,
24277) -> AnyElement {
24278    h_flex()
24279        .h(line_height)
24280        .mr_1()
24281        .gap_1()
24282        .px_0p5()
24283        .pb_1()
24284        .border_x_1()
24285        .border_b_1()
24286        .border_color(cx.theme().colors().border_variant)
24287        .rounded_b_lg()
24288        .bg(cx.theme().colors().editor_background)
24289        .gap_1()
24290        .block_mouse_except_scroll()
24291        .shadow_md()
24292        .child(if status.has_secondary_hunk() {
24293            Button::new(("stage", row as u64), "Stage")
24294                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24295                .tooltip({
24296                    let focus_handle = editor.focus_handle(cx);
24297                    move |window, cx| {
24298                        Tooltip::for_action_in(
24299                            "Stage Hunk",
24300                            &::git::ToggleStaged,
24301                            &focus_handle,
24302                            window,
24303                            cx,
24304                        )
24305                    }
24306                })
24307                .on_click({
24308                    let editor = editor.clone();
24309                    move |_event, _window, cx| {
24310                        editor.update(cx, |editor, cx| {
24311                            editor.stage_or_unstage_diff_hunks(
24312                                true,
24313                                vec![hunk_range.start..hunk_range.start],
24314                                cx,
24315                            );
24316                        });
24317                    }
24318                })
24319        } else {
24320            Button::new(("unstage", row as u64), "Unstage")
24321                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24322                .tooltip({
24323                    let focus_handle = editor.focus_handle(cx);
24324                    move |window, cx| {
24325                        Tooltip::for_action_in(
24326                            "Unstage Hunk",
24327                            &::git::ToggleStaged,
24328                            &focus_handle,
24329                            window,
24330                            cx,
24331                        )
24332                    }
24333                })
24334                .on_click({
24335                    let editor = editor.clone();
24336                    move |_event, _window, cx| {
24337                        editor.update(cx, |editor, cx| {
24338                            editor.stage_or_unstage_diff_hunks(
24339                                false,
24340                                vec![hunk_range.start..hunk_range.start],
24341                                cx,
24342                            );
24343                        });
24344                    }
24345                })
24346        })
24347        .child(
24348            Button::new(("restore", row as u64), "Restore")
24349                .tooltip({
24350                    let focus_handle = editor.focus_handle(cx);
24351                    move |window, cx| {
24352                        Tooltip::for_action_in(
24353                            "Restore Hunk",
24354                            &::git::Restore,
24355                            &focus_handle,
24356                            window,
24357                            cx,
24358                        )
24359                    }
24360                })
24361                .on_click({
24362                    let editor = editor.clone();
24363                    move |_event, window, cx| {
24364                        editor.update(cx, |editor, cx| {
24365                            let snapshot = editor.snapshot(window, cx);
24366                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24367                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24368                        });
24369                    }
24370                })
24371                .disabled(is_created_file),
24372        )
24373        .when(
24374            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24375            |el| {
24376                el.child(
24377                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24378                        .shape(IconButtonShape::Square)
24379                        .icon_size(IconSize::Small)
24380                        // .disabled(!has_multiple_hunks)
24381                        .tooltip({
24382                            let focus_handle = editor.focus_handle(cx);
24383                            move |window, cx| {
24384                                Tooltip::for_action_in(
24385                                    "Next Hunk",
24386                                    &GoToHunk,
24387                                    &focus_handle,
24388                                    window,
24389                                    cx,
24390                                )
24391                            }
24392                        })
24393                        .on_click({
24394                            let editor = editor.clone();
24395                            move |_event, window, cx| {
24396                                editor.update(cx, |editor, cx| {
24397                                    let snapshot = editor.snapshot(window, cx);
24398                                    let position =
24399                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24400                                    editor.go_to_hunk_before_or_after_position(
24401                                        &snapshot,
24402                                        position,
24403                                        Direction::Next,
24404                                        window,
24405                                        cx,
24406                                    );
24407                                    editor.expand_selected_diff_hunks(cx);
24408                                });
24409                            }
24410                        }),
24411                )
24412                .child(
24413                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24414                        .shape(IconButtonShape::Square)
24415                        .icon_size(IconSize::Small)
24416                        // .disabled(!has_multiple_hunks)
24417                        .tooltip({
24418                            let focus_handle = editor.focus_handle(cx);
24419                            move |window, cx| {
24420                                Tooltip::for_action_in(
24421                                    "Previous Hunk",
24422                                    &GoToPreviousHunk,
24423                                    &focus_handle,
24424                                    window,
24425                                    cx,
24426                                )
24427                            }
24428                        })
24429                        .on_click({
24430                            let editor = editor.clone();
24431                            move |_event, window, cx| {
24432                                editor.update(cx, |editor, cx| {
24433                                    let snapshot = editor.snapshot(window, cx);
24434                                    let point =
24435                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24436                                    editor.go_to_hunk_before_or_after_position(
24437                                        &snapshot,
24438                                        point,
24439                                        Direction::Prev,
24440                                        window,
24441                                        cx,
24442                                    );
24443                                    editor.expand_selected_diff_hunks(cx);
24444                                });
24445                            }
24446                        }),
24447                )
24448            },
24449        )
24450        .into_any_element()
24451}
24452
24453pub fn multibuffer_context_lines(cx: &App) -> u32 {
24454    EditorSettings::try_get(cx)
24455        .map(|settings| settings.excerpt_context_lines)
24456        .unwrap_or(2)
24457        .min(32)
24458}